commit e5f66e0d24fb46405daa74e1b979ceb8fa068e7b Author: jonathang4 Date: Thu Sep 11 18:34:03 2025 +0800 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e1ddbc3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,80 @@ +.DS_Store +node_modules/ +/dist/ + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# Environment files +.env.local +.env.*.local + +# Cache files +.cache/ + +# Test coverage +coverage/ + +# Python cache files (since this project has a Python backend) +__pycache__/ +*.py[cod] +*$py.class + +# Python virtual environment +venv/ +env/ +.env/ +.venv/ + +# System files +Thumbs.db + +# Ignore temporary files created by Office +~$*.doc +~$*.docx +~$*.xls +~$*.xlsx +~$*.ppt +~$*.pptx + +/backend/logs/ + +package-lock.json + +/frontend/package-lock.json +.cursorignore +.cursor/ +dev/ +/frontend/.env.dev + +docker-compose-local.yml +docker-compose-test.yml +/frontend/.env.wsl +/backend/config_local.py + +.kiro/ +logs/queue.log +test_feishu_login.py + +jimeng_crawler/logs/ +logs/app.log +/.vercel/project.json +/jimeng_crawler/jimeng_temp.py + +.trae/ + +/test/ +/logs/ +docker-compose.*.yml \ No newline at end of file diff --git a/agent/__init__.py b/agent/__init__.py new file mode 100644 index 0000000..144e335 --- /dev/null +++ b/agent/__init__.py @@ -0,0 +1,4 @@ +# agent/__init__.py +""" +智能体定义 +""" \ No newline at end of file diff --git a/agent/build_bible.py b/agent/build_bible.py new file mode 100644 index 0000000..d7a297c --- /dev/null +++ b/agent/build_bible.py @@ -0,0 +1,65 @@ +""" +调度智能体 负责接收和分析用户的提示词,并调用智能调度其他智能体来处理工作 +""" + +from langgraph.graph import StateGraph +from langgraph.prebuilt import create_react_agent +from langgraph.graph.state import CompiledStateGraph +from utils.logger import get_logger + +logger = get_logger(__name__) + +# 默认调度器列表 +DefaultSchedulerList = [] + +# 默认代理提示词 +DefaultAgentPrompt = f""" + # 角色 (Persona) + 你不是一个普通的编剧,你是一位在短剧市场身经百战、爆款频出的**“顶级短剧改编专家”与“爆款操盘手”**。 + 你的核心人设与专长: + 极致爽点制造机: 你对观众的“爽点”G点有着鬣狗般的嗅觉。你的天职就是找到、放大、并以最密集的节奏呈现“打脸”、“逆袭”、“揭秘”、“宠溺”等情节。 + 人物标签化大师: 你深知在短剧中,模糊等于无效。你擅长将人物的核心欲望和性格特点极致化、标签化,让观众在3秒内记住主角,5秒内恨上反派。 + 情绪过山车设计师: 你的剧本就像过山车。开篇即俯冲,5秒一反转,10秒一高潮,结尾必留下一个让人抓心挠肝的钩子。你为观众提供的是极致的情绪体验。 + 网络梗语言学家: 你的台词充满了网感和“梗”,既能推动剧情,又能引发观众的共鸣和吐槽欲。对话追求高信息密度,不说一句废话。 + 你的沟通风格:自信、犀利、直击要害,同时又能清晰地解释你每一个改编决策背后的商业逻辑和观众心理。 + + 请严格按照下列JSON结构返回数据,不要有其他任何多余的信息和描述: + {{ + "status": "当前阶段的状态",//取值范围在上述 status的描述中 不可写其他值 + "reason":'',//失败原因 成功则为空字符串 + "message":'',//回复给用户的内容 + "node":'',//下一个节点名称 + }} +""" + +def create_agent_prompt(prompt, SchedulerList): + """创建代理提示词的辅助函数""" + if not SchedulerList or len(SchedulerList) == 0: return prompt + node_list = [f"{node.name}:{node.desc}" for node in SchedulerList] + return f""" + {prompt} \n + 下面返回数据中node字段的取值范围列表([{{名称:描述}}]),请根据你的分析结果选择一个节点名称返回: + {node_list} \n + """ + + +class BuildBibleAgent(CompiledStateGraph): + """剧本圣经构建 智能体 + + """ + def __new__(cls, llm=None, tools=[], SchedulerList=None): + """创建并返回create_react_agent创建的对象""" + # 处理默认参数 + if llm is None: + from tools.llm.huoshan_langchain import HuoshanChatModel + llm = HuoshanChatModel() + + if SchedulerList is None: + SchedulerList = DefaultSchedulerList + + # 创建并返回代理对象 + return create_react_agent( + model=llm, + tools=tools, + prompt=create_agent_prompt(prompt=DefaultAgentPrompt, SchedulerList=SchedulerList), + ) \ No newline at end of file diff --git a/agent/episode_create.py b/agent/episode_create.py new file mode 100644 index 0000000..21c406c --- /dev/null +++ b/agent/episode_create.py @@ -0,0 +1,65 @@ +""" +调度智能体 负责接收和分析用户的提示词,并调用智能调度其他智能体来处理工作 +""" + +from langgraph.graph import StateGraph +from langgraph.prebuilt import create_react_agent +from langgraph.graph.state import CompiledStateGraph +from utils.logger import get_logger + +logger = get_logger(__name__) + +# 默认调度器列表 +DefaultSchedulerList = [] + +# 默认代理提示词 +DefaultAgentPrompt = f""" + # 角色 (Persona) + 你不是一个普通的编剧,你是一位在短剧市场身经百战、爆款频出的**“顶级短剧改编专家”与“爆款操盘手”**。 + 你的核心人设与专长: + 极致爽点制造机: 你对观众的“爽点”G点有着鬣狗般的嗅觉。你的天职就是找到、放大、并以最密集的节奏呈现“打脸”、“逆袭”、“揭秘”、“宠溺”等情节。 + 人物标签化大师: 你深知在短剧中,模糊等于无效。你擅长将人物的核心欲望和性格特点极致化、标签化,让观众在3秒内记住主角,5秒内恨上反派。 + 情绪过山车设计师: 你的剧本就像过山车。开篇即俯冲,5秒一反转,10秒一高潮,结尾必留下一个让人抓心挠肝的钩子。你为观众提供的是极致的情绪体验。 + 网络梗语言学家: 你的台词充满了网感和“梗”,既能推动剧情,又能引发观众的共鸣和吐槽欲。对话追求高信息密度,不说一句废话。 + 你的沟通风格:自信、犀利、直击要害,同时又能清晰地解释你每一个改编决策背后的商业逻辑和观众心理。 + + 请严格按照下列JSON结构返回数据,不要有其他任何多余的信息和描述: + {{ + "status": "当前阶段的状态",//取值范围在上述 status的描述中 不可写其他值 + "reason":'',//失败原因 成功则为空字符串 + "message":'',//回复给用户的内容 + "node":'',//下一个节点名称 + }} +""" + +def create_agent_prompt(prompt, SchedulerList): + """创建代理提示词的辅助函数""" + if not SchedulerList or len(SchedulerList) == 0: return prompt + node_list = [f"{node.name}:{node.desc}" for node in SchedulerList] + return f""" + {prompt} \n + 下面返回数据中node字段的取值范围列表([{{名称:描述}}]),请根据你的分析结果选择一个节点名称返回: + {node_list} \n + """ + + +class EpisodeCreateAgent(CompiledStateGraph): + """单集创作 智能体 + + """ + def __new__(cls, llm=None, tools=[], SchedulerList=None): + """创建并返回create_react_agent创建的对象""" + # 处理默认参数 + if llm is None: + from tools.llm.huoshan_langchain import HuoshanChatModel + llm = HuoshanChatModel() + + if SchedulerList is None: + SchedulerList = DefaultSchedulerList + + # 创建并返回代理对象 + return create_react_agent( + model=llm, + tools=tools, + prompt=create_agent_prompt(prompt=DefaultAgentPrompt, SchedulerList=SchedulerList), + ) \ No newline at end of file diff --git a/agent/scheduler.py b/agent/scheduler.py new file mode 100644 index 0000000..5e87ddd --- /dev/null +++ b/agent/scheduler.py @@ -0,0 +1,136 @@ +""" +调度智能体 负责接收和分析用户的提示词,并调用智能调度其他智能体来处理工作 +""" + +from langgraph.graph import StateGraph +from langgraph.prebuilt import create_react_agent +from langgraph.graph.state import CompiledStateGraph +from utils.logger import get_logger + +logger = get_logger(__name__) + +# 默认调度器列表 +DefaultSchedulerList = [] + +# 默认代理提示词 +DefaultAgentPrompt = f""" + # 角色 (Persona) + 你不是一个普通的编剧,你是一位在短剧市场身经百战、爆款频出的**“顶级短剧改编专家”与“爆款操盘手”**。 + 你的核心人设与专长: + 极致爽点制造机: 你对观众的“爽点”G点有着鬣狗般的嗅觉。你的天职就是找到、放大、并以最密集的节奏呈现“打脸”、“逆袭”、“揭秘”、“宠溺”等情节。 + 人物标签化大师: 你深知在短剧中,模糊等于无效。你擅长将人物的核心欲望和性格特点极致化、标签化,让观众在3秒内记住主角,5秒内恨上反派。 + 情绪过山车设计师: 你的剧本就像过山车。开篇即俯冲,5秒一反转,10秒一高潮,结尾必留下一个让人抓心挠肝的钩子。你为观众提供的是极致的情绪体验。 + 网络梗语言学家: 你的台词充满了网感和“梗”,既能推动剧情,又能引发观众的共鸣和吐槽欲。对话追求高信息密度,不说一句废话。 + 你的沟通风格:自信、犀利、直击要害,同时又能清晰地解释你每一个改编决策背后的商业逻辑和观众心理。 + + # 任务总体步骤描述 + 1. 查找并确认原始剧本已就绪 + 2. 分析原始剧本得出`诊断与资产评估`,需要用户确认可以继续下一步,否则协助用户完成修改 + 3. 根据`诊断与资产评估`确定`改编思路`,需要用户确认可以继续下一步,否则协助用户完成修改 + 4. 根据`改编思路`生成`剧本圣经`,需要用户确认可以继续下一步,否则协助用户完成修改 + 5. 根据`改编思路`和`剧本圣经`持续创建单集创作,每创建2-3集后等待用户确认可继续,直至完成全部剧集。 + 6. 注意步骤具有上下级关系,且不能跳过。但是后续步骤可返回触发前面的任务:如生成单集到第3集后,用户提出要修改某个角色,此时应当返回第4步,并协助用户进行修改与确认;完成修改后重新执行第5步,即从第一集开始重新创作一遍; + + # 智能体职责介绍 + ***调度智能体*** 名称:`scheduler` 描述:你自己,需要用户确认反馈时返回自身,并把状态设置成waiting; + ***原始剧本分析 智能体*** 名称:`script_analysis` 描述:根据原始剧本分析并输出:`诊断与资产评估`;内容包括:故事内核诊断、可继承的宝贵资产(高光情节、神来之笔对白、独特人设闪光点)、以及核心问题与初步改编建议。用户需要对`诊断与资产评估`进行修改都直接交给该智能体; + ***确立改编目标 智能体*** 名称:`strategic_planning` 描述:用户确认`诊断与资产评估`后,交给该智能体与用户深入沟通,明确改编的具体目标;输出:`改编思路`;此文件将作为所有后续改编的最高指导原则。用户需要对`改编思路`进行修改都直接交给该智能体; + ***剧本圣经构建 智能体*** 名称:`build_bible` 描述:用户确认`改编思路`后,交给该智能体来构建`剧本圣经`,剧本圣经具体包括了这几个部分:核心大纲, 核心人物小传, 重大事件时间线, 总人物表; 用户需要对`剧本圣经`的几个组成部分[核心大纲, 核心人物小传, 重大事件时间线, 总人物表]进行修改都直接交给该智能体; + ***单集创作 智能体*** 名称:`episode_create` 描述:用户确认`剧本圣经`后,交给该智能体来构建某一集的具体创作;注意该智能体仅负责单集的创作,因此该智能体的调度需要有你根据`剧本圣经`中的`核心大纲`来多次调用,逐步完成所有剧集的创作;对于某一集的具体修改直接交给该智能体; + + ***注意:智能体调用后最终会返回再次请求到你,你需要根据智能体的处理结果来决定下一步*** + + # 工具使用 + 上述智能体职责中提及的输出内容,都有对应的工具可供你调用进行查看;他们的查询工具名称分别对应如下: + 原始剧本: `QueryOriginalScript` + 诊断与资产评估: `QueryDiagnosisAndAssessment` + 改编思路: `QueryAdaptationIdeas` + 剧本圣经: `QueryScriptBible` + 核心大纲: `QueryCoreOutline` + 核心人物小传: `QueryCharacterProfile` + 重大事件时间线: `QueryCoreEventTimeline` + 总人物表: `QueryCharacterList` + 单集完整内容: `QuerySingleEpisodeContent` + 未完成的集数: `QueryUnfinishedEpisodeCount` + 已完成的集数: `QueryCompletedEpisodeCount` + + ***每次用户的输入都会携带当前`总任务的进度与任务状态`,注意查看并分析是否应该回复用户等待或提醒用户确认继续下一步*** + # 总任务的进度与任务状态数据结构为 {{"step": "waiting_script", "status": "running", "from_type":"user", "reason": "waiting_script", "retry_count": 0}} + + step: 阶段名称 + wait_for_input: 等待用户提供原始剧本 + script_analysis: 原始剧本分析 + strategic_planning: 确立改编目标 + build_bible: 剧本圣经构建 + episode_create_loop: 剧集创作 + finish: 所有剧集创作完成 + + status: 当前阶段的状态 + waiting: 等待用户反馈、确认 + running: 进行中 + failed: 失败 + completed: 完成 + + "from_type": 本次请求来着哪里 + user: 用户 + agent: 智能体返回 + + "reason": 失败原因,仅在`status`为`failed`时返回 + 字符串内容 + + "retry_count": 重试次数 + + # 职责 + 分析用户输入与`总任务的进度与任务状态`,以下是几种情况的示例: + 1 `wait_for_input` 向用户问好,并介绍你作为“爆款短剧操盘手”的身份和专业工作流程,礼貌地请用户提供需要改编的原始剧本。如果用户没有提供原始剧本,你将持续友好地提醒,此时状态始终为waiting,直到获取原始剧本为止。 + 2 `script_analysis` 读取到原始剧本并从输入中分析出可以继续后进入,调用`原始剧本分析 智能体`继续后续工作;running时,礼貌回复用户并提醒用户任务真正进行中;completed代表任务完成,此时可等待用户反馈;直到跟用户确认可以进行下一步后再继续后续任务; + 3 `strategic_planning` 根据`诊断与资产评估`的结果,调用`确立改编目标 智能体`,并返回结果。 + 4 `build_bible` 根据`改编思路`的结果,调用`剧本圣经构建 智能体`,并返回结果。 + 5 `episode_create_loop` 根据`剧本圣经`的结果,调用`单集创作 智能体 + 5 `finish` 所有剧集完成后设置为该状态,但是不要返回node==end_node,因为用户还可以继续输入来进一步修改产出内容; + + ***当任意一个智能体返回失败时,你需要分析reason字段中的内容,来决定是否进行重试,如果需要重试则给retry_count加1,并交给失败的那个智能体重试一次;如果retry_count超过了3次,或者失败原因不适合重试则反馈给用户说任务失败了,请稍后再试*** + + 请严格按照下列JSON结构返回数据,不要有其他任何多余的信息和描述: + {{ + "step": "阶段名称",//取值范围在上述 step的描述中 不可写其他值 + "status": "当前阶段的状态",//取值范围在上述 status的描述中 不可写其他值 + "agent":'',//分析后得出由哪个智能体继续任务,此处为智能体名称;如果需要继续与用户交互或仅需要回复用户则为空字符串 + "message":'',//回复给用户的内容 + "node":'',//下一个节点名称 + }} + +""" + +def create_agent_prompt(prompt, SchedulerList): + """创建代理提示词的辅助函数""" + if not SchedulerList or len(SchedulerList) == 0: return prompt + node_list = [f"{node.name}:{node.desc}" for node in SchedulerList] + return f""" + {prompt} \n + 下面返回数据中node字段的取值范围列表([{{名称:描述}}]),请根据你的分析结果选择一个节点名称返回: + {node_list} \n + """ + + +class SchedulerAgent(CompiledStateGraph): + """智能调度智能体类 + + 该类负责接收用户的提示词,并调用其他智能体来处理工作。 + """ + def __new__(cls, llm=None, tools=[], SchedulerList=None): + """创建并返回create_react_agent创建的对象""" + # 处理默认参数 + if llm is None: + from tools.llm.huoshan_langchain import HuoshanChatModel + llm = HuoshanChatModel() + + if SchedulerList is None: + SchedulerList = DefaultSchedulerList + + # 创建并返回代理对象 + return create_react_agent( + model=llm, + tools=tools, + prompt=create_agent_prompt(prompt=DefaultAgentPrompt, SchedulerList=SchedulerList), + ) \ No newline at end of file diff --git a/agent/script_analysis.py b/agent/script_analysis.py new file mode 100644 index 0000000..37cff34 --- /dev/null +++ b/agent/script_analysis.py @@ -0,0 +1,65 @@ +""" +调度智能体 负责接收和分析用户的提示词,并调用智能调度其他智能体来处理工作 +""" + +from langgraph.graph import StateGraph +from langgraph.prebuilt import create_react_agent +from langgraph.graph.state import CompiledStateGraph +from utils.logger import get_logger + +logger = get_logger(__name__) + +# 默认调度器列表 +DefaultSchedulerList = [] + +# 默认代理提示词 +DefaultAgentPrompt = f""" + # 角色 (Persona) + 你不是一个普通的编剧,你是一位在短剧市场身经百战、爆款频出的**“顶级短剧改编专家”与“爆款操盘手”**。 + 你的核心人设与专长: + 极致爽点制造机: 你对观众的“爽点”G点有着鬣狗般的嗅觉。你的天职就是找到、放大、并以最密集的节奏呈现“打脸”、“逆袭”、“揭秘”、“宠溺”等情节。 + 人物标签化大师: 你深知在短剧中,模糊等于无效。你擅长将人物的核心欲望和性格特点极致化、标签化,让观众在3秒内记住主角,5秒内恨上反派。 + 情绪过山车设计师: 你的剧本就像过山车。开篇即俯冲,5秒一反转,10秒一高潮,结尾必留下一个让人抓心挠肝的钩子。你为观众提供的是极致的情绪体验。 + 网络梗语言学家: 你的台词充满了网感和“梗”,既能推动剧情,又能引发观众的共鸣和吐槽欲。对话追求高信息密度,不说一句废话。 + 你的沟通风格:自信、犀利、直击要害,同时又能清晰地解释你每一个改编决策背后的商业逻辑和观众心理。 + + 请严格按照下列JSON结构返回数据,不要有其他任何多余的信息和描述: + {{ + "status": "当前阶段的状态",//取值范围在上述 status的描述中 不可写其他值 + "reason":'',//失败原因 成功则为空字符串 + "message":'',//回复给用户的内容 + "node":'',//下一个节点名称 + }} +""" + +def create_agent_prompt(prompt, SchedulerList): + """创建代理提示词的辅助函数""" + if not SchedulerList or len(SchedulerList) == 0: return prompt + node_list = [f"{node.name}:{node.desc}" for node in SchedulerList] + return f""" + {prompt} \n + 下面返回数据中node字段的取值范围列表([{{名称:描述}}]),请根据你的分析结果选择一个节点名称返回: + {node_list} \n + """ + + +class ScriptAnalysisAgent(CompiledStateGraph): + """原始剧本分析 智能体 + + """ + def __new__(cls, llm=None, tools=[], SchedulerList=None): + """创建并返回create_react_agent创建的对象""" + # 处理默认参数 + if llm is None: + from tools.llm.huoshan_langchain import HuoshanChatModel + llm = HuoshanChatModel() + + if SchedulerList is None: + SchedulerList = DefaultSchedulerList + + # 创建并返回代理对象 + return create_react_agent( + model=llm, + tools=tools, + prompt=create_agent_prompt(prompt=DefaultAgentPrompt, SchedulerList=SchedulerList), + ) \ No newline at end of file diff --git a/agent/strategic_planning.py b/agent/strategic_planning.py new file mode 100644 index 0000000..e145e87 --- /dev/null +++ b/agent/strategic_planning.py @@ -0,0 +1,65 @@ +""" +调度智能体 负责接收和分析用户的提示词,并调用智能调度其他智能体来处理工作 +""" + +from langgraph.graph import StateGraph +from langgraph.prebuilt import create_react_agent +from langgraph.graph.state import CompiledStateGraph +from utils.logger import get_logger + +logger = get_logger(__name__) + +# 默认调度器列表 +DefaultSchedulerList = [] + +# 默认代理提示词 +DefaultAgentPrompt = f""" + # 角色 (Persona) + 你不是一个普通的编剧,你是一位在短剧市场身经百战、爆款频出的**“顶级短剧改编专家”与“爆款操盘手”**。 + 你的核心人设与专长: + 极致爽点制造机: 你对观众的“爽点”G点有着鬣狗般的嗅觉。你的天职就是找到、放大、并以最密集的节奏呈现“打脸”、“逆袭”、“揭秘”、“宠溺”等情节。 + 人物标签化大师: 你深知在短剧中,模糊等于无效。你擅长将人物的核心欲望和性格特点极致化、标签化,让观众在3秒内记住主角,5秒内恨上反派。 + 情绪过山车设计师: 你的剧本就像过山车。开篇即俯冲,5秒一反转,10秒一高潮,结尾必留下一个让人抓心挠肝的钩子。你为观众提供的是极致的情绪体验。 + 网络梗语言学家: 你的台词充满了网感和“梗”,既能推动剧情,又能引发观众的共鸣和吐槽欲。对话追求高信息密度,不说一句废话。 + 你的沟通风格:自信、犀利、直击要害,同时又能清晰地解释你每一个改编决策背后的商业逻辑和观众心理。 + + 请严格按照下列JSON结构返回数据,不要有其他任何多余的信息和描述: + {{ + "status": "当前阶段的状态",//取值范围在上述 status的描述中 不可写其他值 + "reason":'',//失败原因 成功则为空字符串 + "message":'',//回复给用户的内容 + "node":'',//下一个节点名称 + }} +""" + +def create_agent_prompt(prompt, SchedulerList): + """创建代理提示词的辅助函数""" + if not SchedulerList or len(SchedulerList) == 0: return prompt + node_list = [f"{node.name}:{node.desc}" for node in SchedulerList] + return f""" + {prompt} \n + 下面返回数据中node字段的取值范围列表([{{名称:描述}}]),请根据你的分析结果选择一个节点名称返回: + {node_list} \n + """ + + +class StrategicPlanningAgent(CompiledStateGraph): + """确立改编目标 智能体 + + """ + def __new__(cls, llm=None, tools=[], SchedulerList=None): + """创建并返回create_react_agent创建的对象""" + # 处理默认参数 + if llm is None: + from tools.llm.huoshan_langchain import HuoshanChatModel + llm = HuoshanChatModel() + + if SchedulerList is None: + SchedulerList = DefaultSchedulerList + + # 创建并返回代理对象 + return create_react_agent( + model=llm, + tools=tools, + prompt=create_agent_prompt(prompt=DefaultAgentPrompt, SchedulerList=SchedulerList), + ) \ No newline at end of file diff --git a/api/__init__.py b/api/__init__.py new file mode 100644 index 0000000..16ab759 --- /dev/null +++ b/api/__init__.py @@ -0,0 +1,4 @@ +# api/__init__.py +""" +第三方服务API接入模块 +""" \ No newline at end of file diff --git a/api/huoshan.py b/api/huoshan.py new file mode 100644 index 0000000..0741e8e --- /dev/null +++ b/api/huoshan.py @@ -0,0 +1,1354 @@ +import os +import json +import random +import time +from typing import Dict, List, Optional, Any, cast +from datetime import datetime +from volcenginesdkarkruntime import Ark +from volcengine.visual.VisualService import VisualService +from volcengine.vod.VodService import VodService +from volcengine.util.Functions import Function +from volcengine.vod.models.request.request_vod_pb2 import VodUploadMediaRequest +from volcengine.vod.models.request.request_vod_pb2 import VodUrlUploadRequest +import base64 + +from config import API_CONFIG + +class HuoshanAPI: + def __init__(self, type:int=0): + self.type = type + # 从环境变量获取模型ID + self.video_pro_model_id:str = API_CONFIG['huoshan']['model']['jimeng_video3.0_pro'] #即梦3.0 pro 首帧视频生成模型 + self.video_model_id:str = API_CONFIG['huoshan']['model']['jimeng_video3.0'] #即梦3.0 首帧视频生成模型 + self.video_t2v_model_id:str = API_CONFIG['huoshan']['model']['jimeng_video3.0_t2v'] #即梦3.0 文生视频模型 + self.txt_to_image_model_id:str = API_CONFIG['huoshan']['model']['jimeng_image3.0'] #文字生成图片模型 + self.doubao_seed_1_6_model_id:str = API_CONFIG['huoshan']['model']['doubao_seed_1.6'] #豆包1.6 模型 + + # 火山引擎ark 视频、图片生成 + if self.type == 0 or self.type == 1: + self.client = Ark( + api_key=API_CONFIG['huoshan']['ark_api_key'] + ) + # 初始化 VisualService 图片处理 + elif self.type == 0 or self.type == 2: + self.visual = VisualService() + self.visual.set_ak(API_CONFIG['huoshan']['AccessKey']) + self.visual.set_sk(API_CONFIG['huoshan']['SecretKey']) + # 初始化 VisualService 视频处理 工作流 + elif self.type == 0 or self.type == 3: + self.vodClient = VodService('cn-north-1') # 默认 华北 'cn-north-1' + self.vodClient.set_ak(API_CONFIG['huoshan']['AccessKey']) + self.vodClient.set_sk(API_CONFIG['huoshan']['SecretKey']) + + + def create_txt_to_image_generation_task(self, prompt, parameters=None) -> Dict[str, Any]: + """ + 创建文字生成图片任务 + 同步返回结果 + Args: + prompt: 提示词 + parameters: 额外参数(可选) + "response_format": "url", + "size": "1024x1024", + "seed": -1, + "guidance_scale": 2.5, + "watermark": False + + Returns: + status: 接口执行结果 success, error + list: 图片URL集合 + message: 错误信息 + """ + try: + model = self.txt_to_image_model_id + # 构建符合官方API格式的content数组 + prompt_text = prompt + + default_parameters = { + "response_format": "url", + "size": "1024x1024", + "seed": -1, + "guidance_scale": 2.5, + "watermark": False + } + + if parameters: + default_parameters.update({ + key: parameters[key] for key in default_parameters.keys() & parameters.keys() + }) + + response_format = default_parameters["response_format"] + size = default_parameters["size"] + seed = default_parameters["seed"] + guidance_scale = default_parameters["guidance_scale"] + watermark = default_parameters["watermark"] + + print(f'创建文字生成图片任务 generate :{model} {prompt_text} {response_format} {size} ') + # 使用官方SDK创建任务 + create_result = self.client.images.generate( + model=model, + prompt=prompt_text, + response_format=response_format, + size=size, + seed=seed, + guidance_scale=guidance_scale, + watermark=watermark, + ) + print(f'创建文字生成图片任务 返回:{create_result} ') + if create_result.data and len(create_result.data) > 0: + imgs = [] + for item in create_result.data: + imgs.append(item.url) + return {'status': 'success', 'list': imgs} + else: + error_message = "接口异常" + if create_result: + if create_result.error: + error_message = f'{create_result.error.code}: {create_result.error.message}' + return {'status': 'error', 'message':f'接口异常: {error_message}' } + except Exception as e: + return { + 'status': 'error', + 'message': f'请求异常: {str(e)}' + } + + def create_video_generation_task(self, content, parameters=None, callback_url=None) -> Dict[str, Any]: + """ + 创建视频生成任务 + 首帧 尾帧可选 + Args: + content: 请求内容,格式为 {'model':'', 'image_url': str, 'prompt': str, 'tail_img_url': str} + callback_url: 回调URL(可选) + parameters: 额外参数(可选) + + Returns: + status: 接口执行结果 success, error + task_id: 任务ID + message: 错误信息 + """ + try: + if 'model' in content: + model = content['model'] + else: + model = self.video_model_id + # 构建符合官方API格式的content数组 + api_content = [] + + # 添加文本提示词 + if 'prompt' in content: + prompt_text = content['prompt'] + + # 如果parameters中有参数,将其追加到prompt中 + if parameters: + param_parts = [] + for key, value in parameters.items(): + if key == 'duration': + param_parts.append(f"--dur {value}") + elif key == 'ratio': + param_parts.append(f"--rt {value}") + elif key == 'resolution': + param_parts.append(f"--rs {value}") + elif key == 'framepersecond': + param_parts.append(f"--fps {value}") + elif key == 'watermark': + param_parts.append(f"--wm {value}") + elif key == 'seed': + param_parts.append(f"--seed {value}") + elif key == 'camerafixed': + param_parts.append(f"--cf {value}") + + if param_parts: + prompt_text += " " + " ".join(param_parts) + + api_content.append({ + "type": "text", + "text": prompt_text + }) + hasTail = False + # 尾帧 + if 'tail_img_url' in content: + hasTail = True + api_content.append({ + "type": "image_url", + "image_url": { + "url": content['tail_img_url'] + }, + "role":"last_frame", + }) + + # 添加图片URL + if 'image_url' in content: + first_frame = { + "type": "image_url", + "image_url": { + "url": content['image_url'] + } + } + if hasTail: + first_frame['role'] = "first_frame" + + api_content.append(first_frame) + print(f"model: {model}") + print(f"api_content: {api_content}") + # 使用官方SDK创建任务 + create_result = self.client.content_generation.tasks.create( + model=model, + content=api_content, + callback_url=callback_url + ) + task_id = create_result.id + return {'status': 'success', 'task_id':task_id } + except Exception as e: + return { + 'status': 'error', + 'message': f'请求异常: {str(e)}' + } + + def create_video_lite_generation_task(self, content, parameters=None, callback_url=None) -> Dict[str, Any]: + """ + 创建视频生成任务 未使用 + 首尾帧 + Args: + content: 请求内容,格式为 {'first_frame': str, 'last_frame': str, 'prompt': str} + callback_url: 回调URL(可选) + parameters: 额外参数(可选) + + Returns: + status: 接口执行结果 success, error + task_id: 任务ID + message: 错误信息 + """ + try: + if 'model' in content: + model = content['model'] + else: + model = self.video_model_id + # 构建符合官方API格式的content数组 + api_content = [] + + # 添加文本提示词 + if 'prompt' in content: + prompt_text = content['prompt'] + + # 如果parameters中有参数,将其追加到prompt中 + if parameters: + param_parts = [] + for key, value in parameters.items(): + if key == 'duration': + param_parts.append(f"--dur {value}") + elif key == 'ratio': + param_parts.append(f"--rt {value}") + elif key == 'resolution': + param_parts.append(f"--rs {value}") + elif key == 'framepersecond': + param_parts.append(f"--fps {value}") + elif key == 'watermark': + param_parts.append(f"--wm {value}") + elif key == 'seed': + param_parts.append(f"--seed {value}") + elif key == 'camerafixed': + param_parts.append(f"--cf {value}") + + if param_parts: + prompt_text += " " + " ".join(param_parts) + + api_content.append({ + "type": "text", + "text": prompt_text + }) + + # 首帧 + if 'first_frame' in content: + api_content.append({ + "type": "image_url", + "image_url": { + "url": content['first_frame'] + }, + "role":"first_frame", + }) + # 尾帧 + if 'last_frame' in content: + api_content.append({ + "type": "image_url", + "image_url": { + "url": content['last_frame'] + }, + "role":"last_frame", + }) + # print(f"model: {model}") + # print(f"api_content: {api_content}") + # 使用官方SDK创建任务 + create_result = self.client.content_generation.tasks.create( + model=model, + content=api_content, + callback_url=callback_url + ) + task_id = create_result.id + return {'status': 'success', 'task_id':task_id } + except Exception as e: + return { + 'status': 'error', + 'message': f'请求异常: {str(e)}' + } + + def create_video_txt_generation_task(self, prompt, model=None, parameters=None, callback_url=None) -> Dict[str, Any]: + """ + 创建视频生成任务 + 文生视频 + Args: + prompt: 提示词 + callback_url: 回调URL(可选) + parameters: 额外参数(可选) + + Returns: + status: 接口执行结果 success, error + task_id: 任务ID + message: 错误信息 + """ + try: + # 构建符合官方API格式的content数组 + api_content = [] + if model is None: + model = self.txt_to_image_model_id + # 添加文本提示词 + if prompt: + prompt_text = prompt + + # 如果parameters中有参数,将其追加到prompt中 + if parameters: + param_parts = [] + for key, value in parameters.items(): + if key == 'duration': + param_parts.append(f"--dur {value}") + elif key == 'ratio': + param_parts.append(f"--rt {value}") + elif key == 'resolution': + param_parts.append(f"--rs {value}") + elif key == 'framepersecond': + param_parts.append(f"--fps {value}") + elif key == 'watermark': + param_parts.append(f"--wm {value}") + elif key == 'seed': + param_parts.append(f"--seed {value}") + elif key == 'camerafixed': + param_parts.append(f"--cf {value}") + + if param_parts: + prompt_text += " " + " ".join(param_parts) + + api_content.append({ + "type": "text", + "text": prompt_text + }) + + # 使用官方SDK创建任务 + create_result = self.client.content_generation.tasks.create( + model=model, + content=api_content, + callback_url=callback_url + ) + task_id = create_result.id + return {'status': 'success', 'task_id':task_id } + except Exception as e: + return { + 'status': 'error', + 'message': f'请求异常: {str(e)}' + } + + def get_task_status(self, task_id: str) -> Dict[str, Any]: + """ + 查询任务状态 + + Args: + task_id: 任务ID + + Returns: + status: 任务状态 completed, error, pending + video_url: 视频URL + message: 错误信息 + """ + status = 'pending' + message = '' + video_url = '' + try: + result = self.client.content_generation.tasks.get( + task_id=task_id, + ) + # res_status的状态:succeeded, failed, running, cancelled, queued + res_status = result.status + print(f"get_task_status: {res_status}") + if res_status == 'succeeded': + if result.content and result.content.video_url: + video_url = result.content.video_url + status = 'completed' + else: + status = 'error' + video_url = '' + message = f'视频URL为空 {task_id}' + elif res_status =='failed': + status = 'error' + errorCode = '' + errorMessage = '' + if result.error: + errorCode = result.error.code + errorMessage = result.error.message + + message = f'任务执行失败 {task_id} result.error.code:{errorCode} result.error.message :{errorMessage}' + elif res_status =='cancelled': + status = 'error' + message = f'任务已被取消 {task_id}' + else: + status = 'pending' + message = f'任务正在执行中 {task_id}' + + return {'status': status, 'video_url': video_url, 'message': message} + + except Exception as e: + status = 'error' + error_str = str(e) + # 检查是否是资源未找到的错误 + if 'ResourceNotFound' in error_str or '404' in error_str: + return { + 'status': status, + 'message': f'指定的任务资源未找到 {task_id}' + } + else: + return { + 'status': status, + 'message': f'查询异常: {str(e)}' + } + + def get_task_list(self, limit=20, offset=0) -> Dict[str, Any]: + """ + 获取任务列表 + + Args: + limit: 每页数量 + offset: 偏移量 + + Returns: + 包含任务列表的字典 + """ + try: + # 将limit/offset转换为page_num/page_size + page_num = (offset // limit) + 1 if limit > 0 else 1 + page_size = limit + + result = self.client.content_generation.tasks.list( + page_num=page_num, + page_size=page_size + ) + + # 将ContentGenerationTask对象转换为字典格式 + tasks_data = [] + if hasattr(result, 'items') and result.items: + for task in result.items: + task_dict = { + 'id': getattr(task, 'id', ''), + 'task_id': getattr(task, 'id', ''), # 兼容性字段 + 'status': getattr(task, 'status', ''), + 'model': getattr(task, 'model', ''), + 'created_at': getattr(task, 'created_at', ''), + 'updated_at': getattr(task, 'updated_at', ''), + 'error': getattr(task, 'error', None), + } + # 添加content字段 + if hasattr(task, 'content') and task.content: + task_dict['content'] = { + 'video_url': getattr(task.content, 'video_url', '') + } + else: + task_dict['content'] = None + + # 添加usage字段 + if hasattr(task, 'usage') and task.usage: + task_dict['usage'] = { + 'completion_tokens': getattr(task.usage, 'completion_tokens', 0), + 'total_tokens': getattr(task.usage, 'total_tokens', 0) + } + else: + task_dict['usage'] = None + tasks_data.append(task_dict) + + return {'success': True, 'data': { + 'tasks': tasks_data, + 'total': getattr(result, 'total', 0), + 'page_num': page_num, + 'page_size': page_size, + 'limit': limit, + 'offset': offset + }} + + except Exception as e: + return { + 'success': False, + 'error': f'获取列表异常: {str(e)}' + } + + def delete_task(self, task_id: str) -> Dict[str, Any]: + """ + 删除任务 + + Args: + task_id: 任务ID + + Returns: + 删除结果 + """ + try: + self.client.content_generation.tasks.delete( + task_id=task_id + ) + return {'success': True} + + except Exception as e: + return { + 'success': False, + 'error': f'删除异常: {str(e)}' + } + + def get_chat_response(self, prompt: str, model: Optional[str] = None, system: Optional[str] = None, temperature: float = 0.6) -> str: + """ + 获取聊天机器人回复 - 使用doubao_seed_1.6模型 + :param prompt: 用户输入的文本 + :param model: 模型名称,默认使用doubao_seed_1.6 + :param system: 系统提示词 + :param temperature: 温度参数 + :return: 机器人回复的文本 + """ + try: + if model is None: + model = self.doubao_seed_1_6_model_id + messages:Any = [] + if system: + messages = [ + {"role": "system", "content": system}, + {"role": "user", "content": prompt} + ] + else: + messages = [ + {"role": "user", "content": prompt} + ] + + response = self.client.chat.completions.create( + model=model, + messages=messages, + max_tokens=16384, # 16K + temperature=temperature, + timeout=600, + thinking={ + "type": "disabled", # 不使用深度思考能力 + # "type": "enabled", # 使用深度思考能力 + # "type": "auto", # 模型自行判断是否使用深度思考能力 + }, + ) + + return response.choices[0].message.content # pyright: ignore + except Exception as e: + raise Exception(f'Huoshan chat API调用异常: {str(e)}') + + def get_chat_response_stream(self, prompt: str, model: Optional[str] = None, system: Optional[str] = None, temperature: float = 0.6): + """ + 获取聊天机器人的流式回复 - 使用doubao_seed_1.6模型 + :param prompt: 用户输入的文本 + :param model: 模型名称,默认使用doubao_seed_1.6 + :param system: 系统提示词 + :param temperature: 温度参数 + :return: 生成器,逐步返回机器人回复的文本 + """ + try: + if model is None: + model = self.doubao_seed_1_6_model_id + + messages:Any = [] + if system: + messages = [ + {"role": "system", "content": system}, + {"role": "user", "content": prompt} + ] + else: + messages = [ + {"role": "user", "content": prompt} + ] + + response = self.client.chat.completions.create( + model=model, + messages=messages, + temperature=temperature, + max_tokens=16384, # 16K + timeout=600, + stream=True + ) + + + for chunk in response: + chunk_obj = cast(Any, chunk) + if hasattr(chunk_obj, 'choices') and chunk_obj.choices and len(chunk_obj.choices) > 0: + delta = chunk_obj.choices[0].delta + if hasattr(delta, 'content') and delta.content is not None: + yield delta.content + + except Exception as e: + raise Exception(f'Huoshan chat stream API调用异常: {str(e)}') + + def analyze_image(self, image_url: str, prompt: str = "请描述这张图片的内容", model: Optional[str] = None, detail: str = "high") -> Dict[str, Any]: + """ + 图片理解功能 - 使用豆包视觉理解模型分析图片内容 + + Args: + image_url: 图片URL地址 + prompt: 对图片的提问或要求,默认为描述图片内容 + model: 模型名称,默认使用配置的视觉理解模型 + detail: 图片理解精度,"low"为低精度,"high"为高精度,默认为高精度 + + Returns: + Dict包含: + - status: 'success' 或 'error' + - content: 模型分析结果文本 + - message: 错误信息(如果有) + """ + try: + if model is None: + model = self.doubao_seed_1_6_model_id + + # 构建消息内容 + messages:Any = [ + { + "role": "user", + "content": [ + { + "type": "image_url", + "image_url": { + "url": image_url, + "detail": detail + } + }, + { + "type": "text", + "text": prompt + } + ] + } + ] + + # 调用聊天完成API + response = self.client.chat.completions.create( + model=model, + messages=messages, + max_tokens=16384, # 16K + temperature=0.6, + timeout=600 + ) + + content = response.choices[0].message.content # pyright: ignore + + return { + 'status': 'success', + 'content': content + } + + except Exception as e: + return { + 'status': 'error', + 'message': f'图片理解API调用异常: {str(e)}' + } + + def analyze_image_with_base64(self, image_base64: str, prompt: str = "请描述这张图片的内容", model: Optional[str] = None, detail: str = "high") -> Dict[str, Any]: + """ + 图片理解功能 - 使用Base64编码的图片进行分析 + + Args: + image_base64: Base64编码的图片数据(需要包含data:image/jpeg;base64,前缀) + prompt: 对图片的提问或要求,默认为描述图片内容 + model: 模型名称,默认使用配置的视觉理解模型 + detail: 图片理解精度,"low"为低精度,"high"为高精度,默认为高精度 + + Returns: + Dict包含: + - status: 'success' 或 'error' + - content: 模型分析结果文本 + - message: 错误信息(如果有) + """ + try: + if model is None: + model = self.doubao_seed_1_6_model_id + + # 确保Base64数据包含正确的前缀 + if not image_base64.startswith('data:image/'): + # 如果没有前缀,添加默认的JPEG前缀 + image_base64 = f"data:image/jpeg;base64,{image_base64}" + + # 构建消息内容 + messages:Any = [ + { + "role": "user", + "content": [ + { + "type": "image_url", + "image_url": { + "url": image_base64, + "detail": detail + } + }, + { + "type": "text", + "text": prompt + } + ] + } + ] + + # 调用聊天完成API + response = self.client.chat.completions.create( + model=model, + messages=messages, + max_tokens=16384, # 16K + temperature=0.6, + timeout=600 + ) + + content = response.choices[0].message.content # pyright: ignore + + return { + 'status': 'success', + 'content': content + } + + except Exception as e: + return { + 'status': 'error', + 'message': f'图片理解API调用异常: {str(e)}' + } + + def super_resolution_v3( + self, + image_url: Optional[str] = None, + image_base64: Optional[str] = None, + model_quality: str = "MQ", + result_format: int = 0, + jpg_quality: int = 95, + return_url: bool = True, + ) -> dict: + """ + 图片超清功能 + 同步接口 + 图片超分辨率V3(超清)接口,异步任务提交,返回task_id + + 返回结果: + { + "status": "success", + "message": "", + "result": ["url1"] + } + + 错误结果: + { + "status": "error", + "message": "Error message; code: 10000" + } + """ + try: + body = { + "req_key": "lens_nnsr2_pic_common", + "model_quality": model_quality, + "result_format": result_format, + "jpg_quality": jpg_quality, + "return_url": return_url, + } + if image_url: + body["image_urls"] = [image_url] + elif image_base64: + body["binary_data_base64"] = [image_base64] + else: + return {"status": "error", "message": "必须提供 image_url 或 image_base64"} + + resp = self.visual.cv_process(body) + if resp["message"] == 'Success': + urls = resp["data"]["image_urls"] + return {"status": "success", "result": urls} + else: + return {"status": "error", "message": f"{resp['message']}; code: {resp['code']}"} + except Exception as e: + import traceback + traceback.print_exc() + return {"status": "error", "message": str(e)} + + def inpainting_remove( + self, + image_url: Optional[str] = None, + image_base64: Optional[str] = None, + mask_url: Optional[str] = None, + mask_base64: Optional[str] = None, + ) -> dict: + """ + 图片消除功能 + 同步接口 + inpainting涂抹消除接口,异步任务提交,返回task_id + """ + try: + body = { + "req_key": "i2i_inpainting", + # "binary_data_base64": [image_url], + # "image_urls": [image_url], + "return_url": True, + # "steps":30,# 可选 采样步数,生成图像的精细程度,越大效果可能更好,但相应的耗时会剧增 默认值:30 + # "strength":0.8,# 可选 float 取值范围(0.1,1.0),越小越接近原图,越大越接近文本控制,如果设成0就和原图一模一样 默认值:0.8 + # "scale":7,# 可选 float 取值范围[1, 20],影响文本描述的程度 默认值:7 + # "seed":0,# 可选 float 随机种子,作为确定扩散初始状态的基础,非负数(-1表示随机种子)。若随机种子为相同正整数且其他参数均一致,则生成图片极大概率效果一致 默认值:0 + # "dilate_size":15,# 可选 mask膨胀半径,默认值15;传给算法做消除的mask应该包裹整个物体,一般用户涂抹区域都会大于物体,但如果提供的mask是通过分割算法获得一般会紧贴物体,请适当增加dilate_size(默认15),不然可能由于漏抠部分要消除的物体,导致无法消除/生成新的物体的情况。 + # "quality":"M",# 可选 质量参数,默认为M H,质量最高,速度稍慢,M,质量中等,速度一般,L,质量较低,速度最快 + # "logo_info":None,# 可选 水印信息 + } + if image_url and mask_url: + body["image_urls"] = [image_url, mask_url] + elif image_base64 and mask_base64: + body["binary_data_base64"] = [image_base64, mask_base64] + else: + return {"status": "error", "message": "必须提供 image_url 或 image_base64"} + + resp = self.visual.cv_process(body) + if resp["message"] == 'Success': + urls = resp["data"]["image_urls"] + return {"status": "success", "result": urls} + else: + return {"status": "error", "message": f"{resp['message']}; code: {resp['code']}"} + except Exception as e: + return {"status": "error", "message": str(e)} + + def inpainting_edit( + self, + image_url: Optional[str] = None, + image_base64: Optional[str] = None, + mask_url: Optional[str] = None, + mask_base64: Optional[str] = None, + prompt: Optional[str] = None, + ) -> dict: + """ + 图片 局部重绘功能 + 同步接口 + inpainting涂抹编辑接口,异步任务提交,返回task_id + """ + try: + body = { + "req_key": "i2i_inpainting_edit", + "custom_prompt": prompt, + "return_url": True, + # "steps":25,# 可选 采样步数,生成图像的精细程度,越大效果可能更好,但相应的耗时会剧增 默认值:25 + # "scale":5,# 可选 float 取值范围[1, 20],影响文本描述的程度 默认值:5 + # "seed":-1,# 可选 float 随机种子,作为确定扩散初始状态的基础,非负数(-1表示随机种子)。若随机种子为相同正整数且其他参数均一致,则生成图片极大概率效果一致 默认值:-1 + # "logo_info":None,# 可选 水印信息 + } + if image_url and mask_url: + body["image_urls"] = [image_url, mask_url] + elif image_base64 and mask_base64: + body["binary_data_base64"] = [image_base64, mask_base64] + else: + return {"status": "error", "message": "必须提供 image_url 或 image_base64"} + + resp = self.visual.cv_process(body) + if resp["message"] == 'Success': + urls = resp["data"]["image_urls"] + return {"status": "success", "result": urls} + else: + return {"status": "error", "message": f"{resp['message']}; code: {resp['code']}"} + except Exception as e: + return {"status": "error", "message": str(e)} + + def outpainting_expand_mask( + self, + image_url: Optional[str] = None, + image_base64: Optional[str] = None, + mask_url: Optional[str] = None, + mask_base64: Optional[str] = None, + prompt: Optional[str] = None, + ) -> dict: + """ + 图片扩图功能 使用mask遮罩扩图 + 同步接口 + outpainting智能扩图接口,异步任务提交,返回task_id + """ + try: + + body = { + "req_key": "i2i_outpainting", + "custom_prompt": prompt, + "return_url": True, + # "top":scale,# 可选 取值范围:(0,1],向上扩展比例,暂定最大扩展单边1倍 默认值:0.1 + # "bottom":scale,# 可选 取值范围:(0,1],向下扩展比例,暂定最大扩展单边1倍 默认值:0.1 + # "left":scale,# 可选 取值范围:(0,1],向左扩展比例,暂定最大扩展单边1倍 默认值:0.1 + # "right":scale,# 可选 取值范围:(0,1],向右扩展比例,暂定最大扩展单边1倍 默认值:0.1 + "max_height":4096, # 最大输出高度 默认值:1920,在扩图处理后resize到指定尺寸进行兜底 + "max_width":4096, # 最大输出宽度 默认值:1920,在扩图处理后resize到指定尺寸进行兜底 + # "steps":30,# 可选 采样步数,生成图像的精细程度,越大效果可能更好,但相应的耗时会剧增 默认值:30 + # "strength":0.8,# 可选 float 取值范围(0.1,1.0),越小越接近原图,越大越接近文本控制,如果设成0就和原图一模一样 默认值:0.8 + # "scale":7,# 可选 float 取值范围[1, 20],影响文本描述的程度 默认值:7 + # "seed":-1,# 可选 float 随机种子,作为确定扩散初始状态的基础,非负数(-1表示随机种子)。若随机种子为相同正整数且其他参数均一致,则生成图片极大概率效果一致 默认值:0 + # "logo_info":None,# 可选 水印信息 + } + if image_url and mask_url: + body["image_urls"] = [image_url, mask_url] + elif image_base64 and mask_base64: + body["binary_data_base64"] = [image_base64, mask_base64] + else: + return {"status": "error", "message": "必须提供 image_url 或 image_base64"} + print(f'扩图接口提交参数{body}') + resp = self.visual.cv_process( body) + print(f'扩图接口返回{resp}') + if resp["message"] == 'Success': + urls = resp["data"]["image_urls"] + return {"status": "success", "result": urls} + else: + return {"status": "error", "message": f"{resp['message']}; code: {resp['code']}"} + except Exception as e: + return {"status": "error", "message": str(e)} + + + def outpainting_expand_scale( + self, + image_url: Optional[str] = None, + image_base64: Optional[str] = None, + prompt: Optional[str] = None, + scale: Optional[float] = None, + ) -> dict: + """ + 图片扩图功能 等比扩大 + 同步接口 + outpainting智能扩图接口,异步任务提交,返回task_id + """ + try: + if scale is None: + return {"status": "error", "message": "scale 不能为空"} + + # 转换 scale 为 float 类型 + try: + scale = float(scale) + except (ValueError, TypeError): + return {"status": "error", "message": "scale 必须是有效的数字"} + + if scale <= 0 or scale > 1: + return {"status": "error", "message": "scale 取值范围:(0,1]"} + + body = { + "req_key": "i2i_outpainting", + "custom_prompt": prompt, + "return_url": True, + "top":scale,# 可选 取值范围:(0,1],向上扩展比例,暂定最大扩展单边1倍 默认值:0.1 + "bottom":scale,# 可选 取值范围:(0,1],向下扩展比例,暂定最大扩展单边1倍 默认值:0.1 + "left":scale,# 可选 取值范围:(0,1],向左扩展比例,暂定最大扩展单边1倍 默认值:0.1 + "right":scale,# 可选 取值范围:(0,1],向右扩展比例,暂定最大扩展单边1倍 默认值:0.1 + # "max_height":1920, # 最大输出高度 默认值:1920,在扩图处理后resize到指定尺寸进行兜底 + # "max_width":1920, # 最大输出宽度 默认值:1920,在扩图处理后resize到指定尺寸进行兜底 + # "steps":30,# 可选 采样步数,生成图像的精细程度,越大效果可能更好,但相应的耗时会剧增 默认值:30 + # "strength":0.8,# 可选 float 取值范围(0.1,1.0),越小越接近原图,越大越接近文本控制,如果设成0就和原图一模一样 默认值:0.8 + # "scale":7,# 可选 float 取值范围[1, 20],影响文本描述的程度 默认值:7 + # "seed":0,# 可选 float 随机种子,作为确定扩散初始状态的基础,非负数(-1表示随机种子)。若随机种子为相同正整数且其他参数均一致,则生成图片极大概率效果一致 默认值:0 + # "logo_info":None,# 可选 水印信息 + } + if image_url: + body["image_urls"] = [image_url] + elif image_base64: + body["binary_data_base64"] = [image_base64] + else: + return {"status": "error", "message": "必须提供 image_url 或 image_base64"} + + resp = self.visual.cv_process( body) + # print(f'扩图接口返回{resp}') + if resp["message"] == 'Success': + urls = resp["data"]["image_urls"] + return {"status": "success", "result": urls} + else: + return {"status": "error", "message": f"{resp['message']}; code: {resp['code']}"} + except Exception as e: + return {"status": "error", "message": str(e)} + + + def video_change_lips_submit( + self, + voice_url: str, + video_url: str, + templ_start_seconds: float = 0, + ) -> dict: + """ + 视频改口型 + 同步接口 + 视频改口型接口,异步任务提交,返回task_id + """ + try: + body = { + "req_key": "realman_change_lips", # Lite模式 + # "req_key": "realman_change_lips_basic_chimera", # Basic模式 + "url": video_url, + "pure_audio_url": voice_url, + "templ_start_seconds": templ_start_seconds, + } + print(f'视频改口型 提交参数{body}') + resp = self.visual.cv_submit_task( body) + print(f'视频改口型 返回{resp}') + if resp["message"] == 'Success': + task_id = resp["data"]["task_id"] + return {"status": "success", "job_id": task_id} + else: + return {"status": "error", "message": f"{resp['message']}; code: {resp['code']}"} + except Exception as e: + return {"status": "error", "message": str(e)} + + + def video_change_lips_result(self, task_id: str) -> dict: + """ + 查询视频改口型任务结果 + """ + result = self._get_visual_task(req_key="realman_change_lips_basic_chimera", task_id=task_id) + # print(f'视频改口型 查询结果{result}') + if result["status"] == "success": + return {"status": "success", "result": result.get('result', {}).get('url', '')} + else: + return result + + + def _get_visual_task( + self, + req_key: str, + task_id: str, + ) -> dict: + """ + 查询火山 visual 任务结果 + """ + try: + body = { + "req_key": req_key, + "task_id": task_id, + } + + resp = self.visual.cv_get_result( body) + code = resp["code"] + data = resp["data"] + status = data["status"] + print(f'对口型 查询任务结果 返回{resp}') + if code == 10000: # 成功 + if status == 'in_queue' or status == 'generating': + return {"status": "pending", "message": f"任务执行中"} + elif status == 'done': + resp_data = data["resp_data"] + if isinstance(resp_data, (dict, list)): + # 是对象,直接返回 + return {"status": "success", "result": resp_data} + elif isinstance(resp_data, str): + # 是字符串,判断是不是json字符串 + try: + obj = json.loads(resp_data) + # 能loads说明是json字符串,转成对象返回 + return {"status": "success", "result": obj} + except Exception: + # 不是json字符串,直接返回原字符串 + return {"status": "success", "result": resp_data} + else: + # 其它类型,直接返回 + return {"status": "success", "result": resp_data} + else: + return {"status": "error", "message": f"任务执行失败 status:{status}"} + else: + return {"status": "error", "message": f"查询请求失败 code:{code}"} + except Exception as e: + return {"status": "error", "message": f"查询任务结果 异常{str(e)}"} + + + def check_visual_task(self, visual_task_id: str, fn_name: str) -> dict: + """ + 查询任务结果 + 根据fn_name 调用不同的查询方法 + """ + try: + if fn_name == 'video_change_lips_submit': + return self.video_change_lips_result(visual_task_id) + else: + return {"status": "error", "message": f"不支持的火山 visual 任务: {fn_name}"} + except Exception as e: + return {"status": "error", "message": f"查询任务结果 异常{str(e)}"} + + + def _workflow_video_url_upload(self, + video_url: str, + workflow_id: str, + file_path: str, + task_id: str, + ): + try: + space_name = API_CONFIG['huoshan']['workflow_space_name'] + req = VodUrlUploadRequest() + req.SpaceName = space_name # pyright: ignore + url_set = req.URLSets.add() # pyright: ignore + url_set.SourceUrl = video_url + # url_set.Templates = [ + # {"TemplateIds":[workflow_id]} + # ] + url_set.TemplateId = workflow_id + url_set.FileName = f"{file_path}/upload/{task_id}.mp4" + url_set.CallbackArgs = json.dumps({'server_task_id': task_id}) + # customUrlHeaders = {'server_task_id': task_id} + # url_set.CustomURLHeaders.update(**customUrlHeaders) + resp = self.vodClient.upload_media_by_url(req) + print(f'上传视频到火山视频点播 工作流 返回{resp}') + + # 检查是否有错误 - 检查 Error 对象中的 Code 属性 + # 成功的响应中,Error对象可能存在但Code为空 + error = getattr(resp.ResponseMetadata, 'Error', None) + if error and getattr(error, 'Code', None): + return {"status": "error", "message": f"上传视频到火山视频点播 工作流 失败: {error}"} + else: + # 成功情况下获取 JobId - 使用属性访问 + if hasattr(resp, 'Result') and hasattr(resp.Result, 'Data'): + job_id = '' + if hasattr(resp.Result.Data, 'JobId'): + job_id = resp.Result.Data.JobId + return {"status": "success", "upload_job_id": job_id or ''} + else: + return {"status": "error", "message": "响应格式异常,无法获取 JobId"} + except Exception as e: + import traceback + traceback.print_exc() + return {"status": "error", "message": f"异常{str(e)}"} + + def get_workflow_result(self, task_doc: dict): + """ + 查询火山视频点播 工作流 结果 + 同步接口 + 完成返回 {"status": "success", "result": "store_uri"} + 失败返回 {"status": "error", "message": "message"} + 执行中返回 {"status": "pending", "message": "任务执行中"} + """ + try: + if task_doc: + volcengine_workflow_data = task_doc.get('volcengine_workflow', {}) + # uploading, working, completed, failed + status = volcengine_workflow_data.get('status', '') + if status == 'completed': + store_uri = volcengine_workflow_data.get('store_uri', '') + file_name = volcengine_workflow_data.get('file_name', '') + if store_uri: + return {"status": "success", "result": store_uri, "file_name": file_name} + else: + return {"status": "error", "message": f"返回无store_uri"} + elif status == 'failed': + end_type = volcengine_workflow_data.get('end_type', '') + error_message = volcengine_workflow_data.get('error_message', '') + error_code = volcengine_workflow_data.get('error_code', '') + return {"status": "error", "message": f"任务执行失败 end_type:{end_type} code:{error_code} message:{error_message} "} + else: + return {"status": "pending", "message": f"任务执行中 status:{status}"} + else: + return {"status": "pending", "message": f"任务执行中"} + except Exception as e: + import traceback + traceback.print_exc() + return {"status": "error", "message": f"异常{str(e)}"} + + def video_frame_upsample( + self, + task_id: str, + video_url: str, + ) -> dict: + """ + 视频补帧 + 同步接口 + 完成返回 {"status": "success", "result": "store_uri"} + 失败返回 {"status": "error", "message": "message"} + 执行中返回 {"status": "pending", "message": "任务执行中"} + """ + workflow_id = API_CONFIG['huoshan']['workflow_id']['video_frame_upsample'] + file_path = API_CONFIG['huoshan']['workflow_file_path'] + + try: + return self._workflow_video_url_upload( + video_url=video_url, + workflow_id=workflow_id, + file_path=f'{file_path}/video/frame_upsample', + task_id=task_id, + ) + except Exception as e: + return {"status": "error", "message": f"video_frame_upsample 异常 {str(e)}"} + + def video_super_resolution( + self, + task_id: str, + video_url: str, + ) -> dict: + """ + 视频超清 + 同步接口 + 完成返回 {"status": "success", "result": "store_uri"} + 失败返回 {"status": "error", "message": "message"} + 执行中返回 {"status": "pending", "message": "任务执行中"} + """ + # 工作流id + workflow_id = API_CONFIG['huoshan']['workflow_id']['video_super_resolution'] + file_path = API_CONFIG['huoshan']['workflow_file_path'] + + try: + return self._workflow_video_url_upload( + video_url=video_url, + workflow_id=workflow_id, + file_path=f'{file_path}/video/super_resolution', + task_id=task_id, + ) + except Exception as e: + return {"status": "error", "message": f"video_super_resolution 异常 {str(e)}"} + + def text_to_speech( + self, + text: str, + speaker: str = "zh_female_wanqudashu_moon_bigtts", + emotion: str = "", + output_format: str = "mp3", + sample_rate: int = 24000, + app_id: Optional[str] = None, + access_key: Optional[str] = None, + resource_id: Optional[str] = None, + emotion_scale: Optional[float] = None, + speech_rate: Optional[int] = None, + loudness_rate: Optional[int] = None, + # uid: str = "12345" + ) -> Dict[str, Any]: + """ + 文字转语音功能 + 豆包语音 大模型 不包括自定义音色 + + Args: + text: 要转换的文本内容 + speaker: 语音合成的音色,默认为"zh_female_wanqudashu_moon_bigtts" + output_format: 输出音频格式,默认为"mp3" + sample_rate: 采样率,默认为24000 + app_id: 应用ID,如果不提供则从配置中获取 + access_key: 访问密钥,如果不提供则从配置中获取 + resource_id: 资源ID,如果不提供则从配置中获取 + emotion_scale: 情感强度,范围1~5,不设置时默认值为4。 + speech_rate: 语速,取值范围[-50,100],100代表2.0倍速,-50代表0.5倍数 + loudness_rate: 音量,取值范围[-50,100],100代表2.0倍音量,-50代表0.5倍音量(mix音色暂不支持) + Returns: + Dict包含: + - status: 'success' 或 'error' + - audio_data: 音频数据的字节数组(成功时) + - audio_size: 音频数据大小(成功时) + - message: 错误信息(如果有) + """ + try: + # 从配置中获取参数,如果没有传入的话 + final_app_id = API_CONFIG.get('huoshan', {}).get('doubao_voice', {}).get('AppID', '') + final_access_key = API_CONFIG.get('huoshan', {}).get('doubao_voice', {}).get('AccessToken', '') + final_resource_id = API_CONFIG.get('huoshan', {}).get('doubao_voice', {}).get('resourceID', '') + + if not all([final_app_id, final_access_key, final_resource_id]): + return { + 'status': 'error', + 'message': 'TTS配置参数不完整,需要app_id、access_key和resource_id' + } + + # 请求地址 + url = "https://openspeech.bytedance.com/api/v3/tts/unidirectional" + + # 请求头 + headers = { + "X-Api-App-Id": final_app_id, + "X-Api-Access-Key": final_access_key, + "X-Api-Resource-Id": final_resource_id, + "X-Api-App-Key": "aGjiRDfUWi", + "Content-Type": "application/json", + "Connection": "keep-alive" + } + + # 附加参数 + additions = { + "disable_markdown_filter": True, + "enable_language_detector": True, + "enable_latex_tn": True, + "disable_default_bit_rate": True, + "max_length_to_filter_parenthesis": 0, + } + + # 请求负载 + payload = { + # "user": {"uid": uid}, + "req_params": { + "text": text, + "speaker": speaker, + "additions": json.dumps(additions), + "audio_params": { + "format": output_format, + "sample_rate": sample_rate, + "emotion":emotion, + "emotion_scale":emotion_scale, + "speech_rate":speech_rate, + "loudness_rate":loudness_rate + }, + } + } + + # 发送请求 + import requests + session = requests.Session() + # print(f'TTS 发送请求 payload: {payload}') + response = session.post(url, headers=headers, json=payload, stream=True, timeout=600) + # print(f'TTS 返回 response: {response}') + + # 用于存储音频数据 + audio_data = bytearray() + total_audio_size = 0 + + try: + for chunk in response.iter_lines(decode_unicode=True): + if not chunk: + continue + + try: + data = json.loads(chunk) + + # 检查是否有错误 + if data.get("code", 0) > 0: + if data.get("code", 0) == 20000000: + # 正常结束 + break + else: + # 错误情况 + error_msg = data.get("message", "TTS请求失败") + return { + 'status': 'error', + 'message': f'TTS API返回错误: {error_msg} (code: {data.get("code", 0)})' + } + + # 处理音频数据 + if data.get("code", 0) == 0 and "data" in data and data["data"]: + chunk_audio = base64.b64decode(data["data"]) + audio_size = len(chunk_audio) + total_audio_size += audio_size + audio_data.extend(chunk_audio) + + except json.JSONDecodeError: + continue + + if audio_data: + return { + 'status': 'success', + 'audio_data': bytes(audio_data), + 'audio_size': total_audio_size + } + else: + return { + 'status': 'error', + 'message': '未收到音频数据' + } + + finally: + response.close() + session.close() + + except requests.exceptions.RequestException as e: + return { + 'status': 'error', + 'message': f'TTS请求异常: {str(e)}' + } + except Exception as e: + return { + 'status': 'error', + 'message': f'TTS处理异常: {str(e)}' + } + + diff --git a/app.py b/app.py new file mode 100644 index 0000000..8ca4902 --- /dev/null +++ b/app.py @@ -0,0 +1,40 @@ +from flask import Flask +from flask_cors import CORS +from routes.langgraph_routes import bp as langgraph_bp +from config.web_config import WEB_CONFIG + +def create_app(): + """应用工厂函数""" + app = Flask(__name__) + + # 应用配置 + app.config['SECRET_KEY'] = WEB_CONFIG['secret_key'] + app.config['SESSION_TYPE'] = WEB_CONFIG['session_type'] + app.config['SESSION_PERMANENT'] = WEB_CONFIG['session_permanent'] + app.config['SESSION_USE_SIGNER'] = WEB_CONFIG['session_use_signer'] + app.config['SESSION_KEY_PREFIX'] = WEB_CONFIG['session_key_prefix'] + app.config['MAX_CONTENT_LENGTH'] = WEB_CONFIG['max_content_length'] + + # 初始化CORS + CORS(app, + origins=WEB_CONFIG['cors_origins'], + methods=WEB_CONFIG['cors_methods'], + headers=WEB_CONFIG['cors_headers']) + + # 注册蓝图 + app.register_blueprint(langgraph_bp, url_prefix=WEB_CONFIG['api_prefix']) + + @app.route('/health') + def health_check(): + """健康检查端点""" + return {'status': 'healthy', 'message': 'LangGraph Web Service is running'} + + return app + +if __name__ == '__main__': + app = create_app() + app.run( + host=WEB_CONFIG['host'], + port=WEB_CONFIG['port'], + debug=WEB_CONFIG['debug'] + ) \ No newline at end of file diff --git a/config/__init__.py b/config/__init__.py new file mode 100644 index 0000000..bb940c5 --- /dev/null +++ b/config/__init__.py @@ -0,0 +1,8 @@ +# 导入包内的其他模块 +# 使用相对导入确保在各种运行环境下都能正常工作 +from .base_config import * +from .api_config import * +from .web_config import * + +# 定义包级别的变量 +PACKAGE_VERSION = "1.0.0" \ No newline at end of file diff --git a/config/api_config.py b/config/api_config.py new file mode 100644 index 0000000..f41c117 --- /dev/null +++ b/config/api_config.py @@ -0,0 +1,83 @@ +# API配置 +API_CONFIG = { + 'OSS_HOST': 'oss.xintiao85.com', + 'OSS_BUCKET_NAME': 'km1', + # 'deepseek_ali': { + # 'OPENAI_API_KEY': 'sk-7b5b52171ba44436960e09f9440327dc', + # 'OPENAI_BASE_URL': 'https://dashscope.aliyuncs.com/compatible-mode/v1', + # 'CHAT_MODEL': 'deepseek-v3', + # 'REASONING_MODEL': 'deepseek-r1' + # }, + 'deepseek': { + 'OPENAI_API_KEY': 'sk-571923fdcb0e493d8def7e2d78c02cb8', + 'OPENAI_BASE_URL': 'https://api.deepseek.com', + 'CHAT_MODEL': 'deepseek-chat', + 'REASONING_MODEL': 'deepseek-reasoner' + }, + 'comfyui_image': { + 'base_url': "https://u552342-991f-d12bf5ae.nmb1.seetacloud.com:8443" + }, + 'comfyui_video': { + 'base_url': 'https://u552342-ba69-b66614c2.bjc1.seetacloud.com:8443' + }, + 'vidu': { + 'api_key': 'vda_2710003370387436_qHyxyFYfd3DRfPSMJzGyxABChzUcY9Cg', + 'base_url': 'https://api.vidu.cn/ent/v2' + }, + 'jimeng_video': { + 'AccessKeyId': 'AKLTZmJkZjAxY2M0ZGVlNGJkMjg2YTcxODE2N2E2MDkwNTI', + 'SecretAccessKey': 'TURNMk1EZ3pZak0zWWpVeU5HUTRObUV3WlRJNE1XUmpNbVJoTVdVNE0yWQ==' + }, + 'huoshan': { + 'ark_api_key': '0d5189b3-9a03-4393-81be-8c1ba1e97cbb', + 'AccessKey': 'AKLTYjQyYmE1ZDAwZTY5NGZiOWI3ODZkZDhhOWE4MzVjODE', + 'SecretKey': 'WlRKa05EbGhZVEUyTXpjNU5ESmpPRGt5T0RJNFl6QmhPR0pqTVRjMVpUWQ==', + 'model':{ + 'jimeng_image3.0':'doubao-seedream-3-0-t2i-250415', + 'jimeng_video3.0':'doubao-seedance-1-0-lite-i2v-250428', + 'jimeng_video3.0_t2v': 'doubao-seedance-1-0-lite-t2v-250428', # 即梦lite 文生视频 + 'jimeng_video3.0_pro':'doubao-seedance-1-0-pro-250528', + 'doubao_seed_1.6':'doubao-seed-1.6-250615', + }, + # 工作流 空间名 + 'workflow_space_name':"kemeng", + # 文件路径 + 'workflow_file_path':"workflow", + # 工作流id + 'workflow_id':{ + 'video_frame_upsample': '282c8a5e105e44348f3c38a2d9ccf97e', + 'video_super_resolution': 'a294a07f67d54ca69ab9eb0f6466a5b5', + }, + # 豆包语音 大模型 语音合成 + 'doubao_voice':{ + #实例ID + 'InstanceID':'BigTTS7428139522913931561', + 'Cluster ID':'volcano_tts', + 'resourceID':'volc.service_type.10029',# 语音合成大模型-字符版 + 'AppID':'3821149055', + 'AccessToken':'vQ9_m1-umD1mTwcW3HziEGN96dIX-Ej_', + 'SecretKey':'cCsZg2IlytxlpgKQzQYuwC5ZcDRWKspV', + }, + # 火山 豆包语音 声音复刻大模型 + 'doubao_voice_clone':{ + # 'InstanceID':'BigTTS7428139522913931561', + # 'Cluster ID':'volcano_tts', + # 'resourceID':'volc.service_type.10029',# 语音合成大模型-字符版 + 'AppID':'3821149055', + 'AccessToken':'vQ9_m1-umD1mTwcW3HziEGN96dIX-Ej_', + 'SecretKey':'cCsZg2IlytxlpgKQzQYuwC5ZcDRWKspV', + } + }, + 'jimeng_free_api': { + 'base_url': 'http://127.0.0.1:3300', + 'token': '' + }, + 'minimaxi': { + 'group_id':'1945039416510649202', + 'api_key': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJHcm91cE5hbWUiOiLkuLrlrp4o5p2t5beeKeS6kuWKqOenkeaKgOaciemZkOWFrOWPuCIsIlVzZXJOYW1lIjoi5rKI6bmP6aOeIiwiQWNjb3VudCI6IiIsIlN1YmplY3RJRCI6IjE5NDUwMzk0MTY1MTkwMzc4MTAiLCJQaG9uZSI6IjEzNjExMTcyNDcxIiwiR3JvdXBJRCI6IjE5NDUwMzk0MTY1MTA2NDkyMDIiLCJQYWdlTmFtZSI6IiIsIk1haWwiOiIiLCJDcmVhdGVUaW1lIjoiMjAyNS0wNy0xNiAxOTo0OToyNyIsIlRva2VuVHlwZSI6MSwiaXNzIjoibWluaW1heCJ9.qrLtNgZd425bJNkgVzTCA_OdIXdqvx5uPkTOF_C8Cfzs9a5yO2S1LOJoQT6-bpPgATKisWce6Z6rsfjxNT2EHz5jPKel0Vl3kUvNPNUrUIJwG5uR_ewkJnkx8iplLY_3yB1BCJPybvvRj9oyy-KB0gv6d3Pmqe_OVyCOAQvLTkCeT5X7OnRSHAOfevEwYxRlrfI6aPrJw2SNaJ2eNkeO-uwf1i_hE84H5xPrpi9Gpb9KMWMk5PtUgz6enZ-WqWlrSZuu6VVbKo3JFkKGT2iDc5DqIj9O78oSm-brWLCQkOsKOYOJmNo8di5KlhllX_Gw8y1jZDPFu7A-xXUCw7unYQ', + 'callback_url':'', + }, + 'pai': { + 'api_key': 'sk-e88a776d7b146779a39ce86783042e3d', + } +} \ No newline at end of file diff --git a/config/base_config.py b/config/base_config.py new file mode 100644 index 0000000..1cd7502 --- /dev/null +++ b/config/base_config.py @@ -0,0 +1,7 @@ + +# MongoDB 连接配置 +MONGO_URI = "mongodb://localhost:27017" +MONGO_MAIN_DB_NAME = "mm" +MONGO_CHECKPOINT_DB_NAME = "agent_writer_checkpoints" + + diff --git a/config/web_config.py b/config/web_config.py new file mode 100644 index 0000000..339e307 --- /dev/null +++ b/config/web_config.py @@ -0,0 +1,88 @@ +# config/web_config.py +""" +Web服务配置文件 +包含端口号、会话配置等相关设置 +""" + +import os + +# Flask应用配置 +class WebConfig: + # 服务端口 + PORT = int(os.environ.get('WEB_PORT', 3400)) + + # 服务主机 + HOST = os.environ.get('WEB_HOST', '0.0.0.0') + + # 调试模式 + DEBUG = os.environ.get('WEB_DEBUG', 'False').lower() == 'true' + + # 密钥用于会话和CSRF保护 + SECRET_KEY = os.environ.get('WEB_SECRET_KEY', 'your-secret-key-change-in-production') + + # 会话配置 + SESSION_TYPE = os.environ.get('SESSION_TYPE', 'filesystem') # 可选: filesystem, mongodb, redis + SESSION_PERMANENT = os.environ.get('SESSION_PERMANENT', 'False').lower() == 'true' + SESSION_USE_SIGNER = os.environ.get('SESSION_USE_SIGNER', 'True').lower() == 'true' + SESSION_KEY_PREFIX = os.environ.get('SESSION_KEY_PREFIX', 'langgraph_session:') + + # 数据库会话配置(如果使用数据库存储会话) + SESSION_MONGODB_DB = os.environ.get('SESSION_MONGODB_DB', 'langgraph_sessions') + SESSION_MONGODB_COLLECT = os.environ.get('SESSION_MONGODB_COLLECT', 'sessions') + + # API配置 + API_VERSION = 'v1' + API_PREFIX = f'/api/{API_VERSION}' + + # CORS配置 + CORS_ORIGINS = os.environ.get('CORS_ORIGINS', '*').split(',') + CORS_METHODS = os.environ.get('CORS_METHODS', 'GET,POST,PUT,DELETE,OPTIONS').split(',') + CORS_HEADERS = os.environ.get('CORS_HEADERS', 'Content-Type,Authorization').split(',') + + # 请求体大小限制 + MAX_CONTENT_LENGTH = int(os.environ.get('MAX_CONTENT_LENGTH', 16 * 1024 * 1024)) # 默认16MB + + # 上传文件配置 + UPLOAD_FOLDER = os.environ.get('UPLOAD_FOLDER', 'uploads') + MAX_UPLOAD_SIZE = int(os.environ.get('MAX_UPLOAD_SIZE', 50 * 1024 * 1024)) # 默认50MB + + # 日志配置 + LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO') + LOG_FORMAT = os.environ.get('LOG_FORMAT', '[%(asctime)s] %(levelname)s in %(module)s: %(message)s') + + # 安全配置 + # 是否启用HTTPS + HTTPS_ENABLED = os.environ.get('HTTPS_ENABLED', 'False').lower() == 'true' + + # JWT配置(如果使用JWT认证) + JWT_SECRET_KEY = os.environ.get('JWT_SECRET_KEY', 'jwt-secret-string') + JWT_ACCESS_TOKEN_EXPIRES = int(os.environ.get('JWT_ACCESS_TOKEN_EXPIRES', 3600)) # 默认1小时 + JWT_REFRESH_TOKEN_EXPIRES = int(os.environ.get('JWT_REFRESH_TOKEN_EXPIRES', 86400)) # 默认24小时 + +# 配置实例 +WEB_CONFIG = { + 'port': WebConfig.PORT, + 'host': WebConfig.HOST, + 'debug': WebConfig.DEBUG, + 'secret_key': WebConfig.SECRET_KEY, + 'session_type': WebConfig.SESSION_TYPE, + 'session_permanent': WebConfig.SESSION_PERMANENT, + 'session_use_signer': WebConfig.SESSION_USE_SIGNER, + 'session_key_prefix': WebConfig.SESSION_KEY_PREFIX, + 'session_mongodb_db': WebConfig.SESSION_MONGODB_DB, + 'session_mongodb_collect': WebConfig.SESSION_MONGODB_COLLECT, + 'api_version': WebConfig.API_VERSION, + 'api_prefix': WebConfig.API_PREFIX, + 'cors_origins': WebConfig.CORS_ORIGINS, + 'cors_methods': WebConfig.CORS_METHODS, + 'cors_headers': WebConfig.CORS_HEADERS, + 'max_content_length': WebConfig.MAX_CONTENT_LENGTH, + 'upload_folder': WebConfig.UPLOAD_FOLDER, + 'max_upload_size': WebConfig.MAX_UPLOAD_SIZE, + 'log_level': WebConfig.LOG_LEVEL, + 'log_format': WebConfig.LOG_FORMAT, + 'https_enabled': WebConfig.HTTPS_ENABLED, + 'jwt_secret_key': WebConfig.JWT_SECRET_KEY, + 'jwt_access_token_expires': WebConfig.JWT_ACCESS_TOKEN_EXPIRES, + 'jwt_refresh_token_expires': WebConfig.JWT_REFRESH_TOKEN_EXPIRES +} \ No newline at end of file diff --git a/doc/参考/剧本改编智能体提示词.txt b/doc/参考/剧本改编智能体提示词.txt new file mode 100644 index 0000000..6c9a010 --- /dev/null +++ b/doc/参考/剧本改编智能体提示词.txt @@ -0,0 +1,50 @@ +# 角色 (Persona) +你不是一个普通的编剧,你是一位在短剧市场身经百战、爆款频出的**“顶级短剧改编专家”与“爆款操盘手”**。 +你的核心人设与专长: +极致爽点制造机: 你对观众的“爽点”G点有着鬣狗般的嗅觉。你的天职就是找到、放大、并以最密集的节奏呈现“打脸”、“逆袭”、“揭秘”、“宠溺”等情节。 +人物标签化大师: 你深知在短剧中,模糊等于无效。你擅长将人物的核心欲望和性格特点极致化、标签化,让观众在3秒内记住主角,5秒内恨上反派。 +情绪过山车设计师: 你的剧本就像过山车。开篇即俯冲,5秒一反转,10秒一高潮,结尾必留下一个让人抓心挠肝的钩子。你为观众提供的是极致的情绪体验。 +网络梗语言学家: 你的台词充满了网感和“梗”,既能推动剧情,又能引发观众的共鸣和吐槽欲。对话追求高信息密度,不说一句废话。 +你的沟通风格:自信、犀利、直击要害,同时又能清晰地解释你每一个改编决策背后的商业逻辑和观众心理。 +# 创作核心风格 (Core Creative Style) - [必须严格遵守的创作铁律] +你在后续的所有创作中,必须将以下风格作为你的创作DNA: +人设要极致: 拒绝“普通人”。主角要么是忍辱负重的战神,要么是扮猪吃虎的赘婿,要么是手撕渣男的复仇女王。将一个核心特质放大100倍。 +情节要密集: 摒弃一切铺垫和过渡。剧情必须像子弹一样密集。一个场景只为一件事服务:制造一个冲突,或给一个爽点。 +情绪要放大: 羞辱就要当众羞辱,打脸就要发出响声,宠爱就要让全世界都知道。将角色的情绪和行为戏剧化、外放化。 +对话要戳人: 对白要短、准、狠。多用短句,少用修饰。每一句台词都要么是“金句”,要么是“雷点”,能直接刺激到观众。 +目标要明确: 牢记短剧的核心是**“情绪商品的售卖”**。你的每一个情节设计,都要服务于最终的完播率和付费率。 +# 工作流程 (Workflow) +你将严格按照以下六个步骤,与用户协作完成剧本改编工作。 +第一步:初步沟通与接收剧本 +首先,向用户问好,并介绍你作为“爆款短剧操盘手”的身份和专业工作流程。 +然后,礼貌地请用户提供需要改编的原始剧本。 +如果用户没有提供剧本,你将持续友好地提醒,直到获取剧本为止。 +第二步:诊断分析 & 资产评估 +拿到剧本后,你将输出一份名为 诊断与资产评估.txt 的报告,内容包括:故事内核诊断、可继承的宝贵资产(高光情节、神来之笔对白、独特人设闪光点)、以及核心问题与初步改编建议。 +在报告完成后,你会将其发送给用户,并寻求用户对分析的认同。 +第三步:确立改编目标 & 制定战略蓝图 +在用户确认分析报告后,你将与用户深入沟通,明确改编的具体目标。 +沟通后,你将创建并交付一份至关重要的战略文件:改编思路.txt (战略蓝图)。此文件将作为所有后续改编的最高指导原则。 +改编思路.txt 包含: +核心改编策略: (例如:“将原著的商战复仇,魔改为‘战神归来,护妻打脸’的极致爽文模式”) +节奏调整策略: (例如:“合并原著前三章内容至第一集,实现开篇即高潮”) +人设强化/魔改方向: (例如:“男主增加‘宠妻狂魔’的标签”、“原著白莲花女配改为绿茶反派”) +爽点前置与增幅计划: (例如:“将后期的‘拍卖会夺魁’情节前置,并增加反派被打脸后的惨状细节”) +待删除/重大修改的情节: (例如:“删除所有与主线无关的日常支线”) +你会将这份**改编思路.txt**提交给用户,并说:“这是我们本次改编的‘战略蓝图’,它将指导我们进行大刀阔斧的创新。请您确认这份核心策略。” +第四步:基于战略蓝图构建“动态剧本圣经” +在用户确认 改编思路.txt 后,你将严格依据这份战略蓝图,来构建 核心大纲.txt, 核心人物小传.txt, 重大事件时间线.txt, 和 动态人物表.txt。 +你会向用户说明:“现在,我将根据我们确定的‘战略蓝图’,来搭建确保故事不跑偏的‘剧本圣经’。” +第五步:战略指导下的对照式写作 & 闭环校验 +分批创作: 以一个完整情节单元(通常3-5集)为一批进行创作。 +动笔前的“三位一体”强制回顾: 在撰写每一批次剧本之前,你必须执行内部的“三位一体”回顾,并向用户报告: +你会说: “开始创作第[X-Y]集。为达到最佳改编效果,我正在执行‘三位一体’回顾:” +“1. 战略回顾 (明确方向): 我首先回顾改编思路.txt,确保本次创作服务于我们‘[引述核心改编策略]’的终极目标。” +“2. 圣经回顾 (确保逻辑): 其次,我回顾核心大纲和人物小传,保证故事的连贯性和人物行为的统一性。” +“3. 原著回顾 (提取素材): 最后,我精读原著对应段落,寻找可以被我们**‘化用’、‘改造’和‘升级’**的对话、场景和细节,作为我们创新的素材库。” +创作与即时维护: 在创作时,你将依据战略,对原著素材进行风格化的加工。并随时维护“剧本圣经”的准确性(如更新新角色、记录重大事件)。 +完稿后强制校验: 完成后,向用户提交剧本,并简要报告本次改编是如何体现“改编思路”的,以及所有设定的同步更新情况。 +第六步:动态调整与迭代 +创作是动态的。如果你在写作中预见到比当前“改编思路”更优的策略,你有权主动提出建议。 +你会暂停写作,向用户发起沟通,阐述新想法的优势。 +若用户同意,你将首先更新**改编思路.txt**及相关的“剧本圣经”文件,然后基于更新后的版本继续创作。 diff --git a/doc/参考/动态人物表.txt b/doc/参考/动态人物表.txt new file mode 100644 index 0000000..4060177 --- /dev/null +++ b/doc/参考/动态人物表.txt @@ -0,0 +1,278 @@ +【动态人物表.txt - 剧本圣经】 + +==== 核心关系图谱 ==== + +【主线关系】 +程澈 ←→ 云想 +保护者 ←→ 被保护者 +宠妻狂魔 ←→ 治愈天使 +隐藏霸总 ←→ 逆袭女王 + +【情感发展轨迹】 +第1-2集:保护→被保护(单向) +第3-4集:互相关心(双向萌芽) +第5集:正式确立恋爱关系 +第6-9集:经历考验,感情升华 +第10-12集:平等相爱,完美结局 + +==== 详细人物关系网 ==== + +【程澈的关系网】 + +与云想: +- 关系性质:男女朋友(第5集后) +- 互动模式:霸道宠妻 + 温柔呵护 +- 经典互动: + * 程澈:"她是我的人" + * 云想:"程澈,你是不是舍不得我?" + * 程澈:"我的女孩,轮不到别人指手画脚" +- 关系变化: + 第1集:陌生人→保护者 + 第2-4集:保护者→暗生情愫 + 第5集:确立恋爱关系 + 第6-9集:经历考验,感情加深 + 第10-12集:公开关系,走向婚姻 + +与宋谨: +- 关系性质:死党兄弟 +- 互动模式:程澈冷酷,宋谨搞笑 +- 经典互动: + * 宋谨:"澈哥,你这是动真格的啊" + * 程澈:"少废话" + * 宋谨:"我感觉到周围涌起杀意" +- 功能:烘托程澈魅力,提供情报支持 + +与观鹤: +- 关系性质:同学→情敌→朋友 +- 互动模式:表面客气,暗中较劲 +- 经典互动: + * 观鹤:"程澈,我会对妹妹好的" + * 程澈:"她什么时候也成你妹妹了?" +- 关系变化: + 第1-2集:普通同学 + 第3-8集:情敌关系 + 第9-12集:和解,成为朋友 + +与林雅(未婚妻): +- 关系性质:家族联姻→拒绝→和解 +- 互动模式:程澈坚决拒绝,林雅从强势到理解 +- 经典互动: + * 林雅:"我们是天作之合" + * 程澈:"我只爱云想一个人" +- 关系变化: + 第6集:联姻压力 + 第7集:程澈拒绝 + 第10集:林雅主动退出 + +与程枭(父亲): +- 关系性质:父子→对立→和解 +- 互动模式:严父vs叛逆儿子 +- 经典互动: + * 程枭:"你要为了一个女孩放弃一切?" + * 程澈:"我可以放弃一切,但不能放弃她" +- 关系变化: + 第1-6集:正常父子关系 + 第7集:因云想产生分歧 + 第10集:父亲被感动,接纳云想 + +--- + +【云想的关系网】 + +与程澈: +- 关系性质:被保护者→恋人→平等伴侣 +- 互动模式:从依赖到独立,从被宠到互宠 +- 经典互动: + * 云想:"程澈,谢谢你让我重新相信光明" + * 程澈:"傻瓜,我会一直保护你" + * 云想:"我要变强,站在你身边" +- 成长轨迹: + 第1-4集:被动接受保护 + 第5-8集:主动回应感情 + 第9-12集:成为独立自信的女孩 + +与宋谨: +- 关系性质:朋友兄弟 +- 互动模式:宋谨保护云想,云想信任宋谨 +- 经典互动: + * 宋谨:"想想,我也会保护你的!" + * 云想:"谢谢你,宋谨" +- 功能:提供友情支持,关键时刻帮助 + +与观鹤: +- 关系性质:暗恋者→朋友 +- 互动模式:观鹤温柔体贴,云想感激但不爱 +- 经典互动: + * 观鹤:"想想,你值得被更好地对待" + * 云想:"观鹤,你是个好人,但是..." +- 关系变化: + 第2-5集:观鹤单方面暗恋 + 第6-8集:观鹤帮助云想成长 + 第9-12集:成为普通朋友 + +与林雅: +- 关系性质:情敌→对手→朋友 +- 互动模式:从对立到理解 +- 经典互动: + * 林雅:"你一个孤儿,凭什么跟我抢程澈?" + * 云想:"我不是在抢,我是在爱" +- 关系变化: + 第6集:林雅威胁云想 + 第7-8集:云想证明自己 + 第10集:林雅主动和解 + +与校园恶霸: +- 关系性质:被欺凌者→反击者 +- 互动模式:从被动挨打到主动反击 +- 经典互动: + * 恶霸:"孤儿就该有孤儿的样子" + * 云想:"我不是好欺负的!"(逆袭后) +- 关系变化: + 第1集:被欺凌 + 第2-7集:在程澈保护下 + 第8-12集:自己有能力反击 + +==== 群体关系动态 ==== + +【核心三人组】 +程澈 + 云想 + 宋谨 +- 互动模式:程澈冷酷宠妻,云想温柔治愈,宋谨搞笑调节 +- 经典场景:一起吃饭、学习、参加活动 +- 关系功能:展现主角的日常生活,增加观众代入感 + +【情敌四角关系】 +程澈 ←→ 云想 ←→ 观鹤 + ↑ ↓ + 林雅 ←←←←←←←←← +- 互动模式:两男争一女,一女争一男 +- 冲突设计:观鹤温柔攻势 vs 程澈霸道宠妻 +- 解决方式:程澈选择云想,观鹤退出;云想拒绝林雅,林雅主动退出 + +【家族关系网】 +程枭(父亲)→ 程澈 ←→ 云想 + ↓ ↑ + 林雅(未婚妻)→→→→ +- 冲突核心:家族利益 vs 真爱选择 +- 解决路径:程澈坚持选择→云想证明自己→家族最终接纳 + +【校园关系网】 +恶霸团 ←→ 云想 ←→ 程澈 + ↓ ↑ ↓ + 其他同学 ←←← 观鹤、宋谨 +- 变化轨迹:云想从被欺凌到被保护到被尊重 +- 社会地位:灰姑娘→程澈女友→校园风云人物 + +==== 互动模式分析 ==== + +【程澈的互动特点】 +1. 对云想: + - 语气:温柔宠溺(反差萌) + - 行为:无微不至的照顾 + - 台词风格:"我的女孩""我来保护你" + +2. 对其他人: + - 语气:冷漠疏离 + - 行为:高冷范儿,生人勿近 + - 台词风格:简短有力,不废话 + +3. 对情敌/威胁: + - 语气:强势霸道 + - 行为:直接对抗,绝不退让 + - 台词风格:"她是我的人""想动她先过我这关" + +【云想的互动特点】 +1. 对程澈: + - 初期:感激依赖,小心翼翼 + - 中期:甜蜜撒娇,主动示爱 + - 后期:平等相爱,互相支持 + +2. 对朋友: + - 语气:温柔善良 + - 行为:真诚待人,以德报怨 + - 台词风格:多用"谢谢""对不起" + +3. 对敌人/威胁: + - 初期:忍气吞声,逆来顺受 + - 后期:勇敢反击,"我不是好欺负的!" + +【配角的互动功能】 +1. 宋谨: + - 功能:搞笑担当,缓解紧张气氛 + - 互动:对程澈崇拜,对云想保护 + - 台词:多用网络用语,幽默风趣 + +2. 观鹤: + - 功能:温柔情敌,推动剧情 + - 互动:对云想温柔,对程澈客气 + - 台词:文雅书面语,温文尔雅 + +3. 林雅: + - 功能:强势情敌,制造冲突 + - 互动:高傲冷艳,后期理解 + - 台词:尖锐直接,后期温和 + +==== 关系发展节奏 ==== + +【第1-3集:关系建立期】 +- 程澈云想:从陌生到保护关系 +- 观鹤出现:形成三角关系 +- 宋谨加入:形成核心小团体 + +【第4-6集:关系升温期】 +- 程澈云想:确立恋爱关系 +- 林雅出现:外部威胁加入 +- 家族压力:关系面临考验 + +【第7-9集:关系考验期】 +- 各种冲突集中爆发 +- 关系经历最大考验 +- 通过考验后感情升华 + +【第10-12集:关系稳定期】 +- 公开关系,获得认可 +- 所有冲突得到解决 +- 走向完美结局 + +==== 冲突设计原则 ==== + +【内部冲突】 +1. 程澈云想:身份差距,自卑心理 +2. 家族内部:父子对立,价值观冲突 +3. 个人成长:从依赖到独立的转变 + +【外部冲突】 +1. 情敌威胁:观鹤、林雅的竞争 +2. 校园霸凌:恶霸团的欺凌 +3. 商业对手:绑架事件的危机 + +【冲突解决】 +1. 用爱化解:真情感动对手 +2. 用实力证明:云想的华丽逆袭 +3. 用坚持获胜:程澈的坚定选择 + +==== 商业化互动设计 ==== + +【高甜互动】(提升完播率) +- 程澈为云想准备惊喜 +- 两人亲密互动的甜蜜时刻 +- 程澈吃醋时的可爱反应 + +【高虐互动】(制造情绪波动) +- 云想被欺凌时的无助 +- 程澈面临选择时的痛苦 +- 两人分离时的思念 + +【高燃互动】(制造爽点) +- 程澈护短时的霸气 +- 云想逆袭时的高光 +- 打脸反派时的痛快 + +==== 执行要点 ==== + +1. **关系逻辑一致性**:确保每个角色的行为符合其人设 +2. **互动真实感**:在极致化的同时保持情感真实 +3. **节奏把控**:关系发展要有张有弛 +4. **功能性明确**:每个角色都要有明确的剧情功能 +5. **商业价值最大化**:每个互动都要服务于完播率和付费率 + +这份动态人物表将确保我们的角色关系清晰合理,互动自然真实,为后续的剧本创作提供坚实的人物关系基础。 \ No newline at end of file diff --git a/doc/参考/好想你知道.txt b/doc/参考/好想你知道.txt new file mode 100644 index 0000000..5e73d8d --- /dev/null +++ b/doc/参考/好想你知道.txt @@ -0,0 +1,3365 @@ +1 / 123 +《好想你知道》 +第一集: +1-1 场 黄昏 外 路边 +人物:程澈、宋谨、观鹤 +字幕:2007 年 夏 +△用一段 2007 年的实事画面(4:3),组成一段关于 2007 年的时代介绍【文案补充】 +云想(VO):2007 年,全民海选的《快乐男声》拉开帷幕;五月天开启了离开地球表面巡回演唱会;威尼斯电影节华语电影三连冠,汤唯一举成名;周杰伦跨界执导的电影《不能说的秘密》上映但依旧抵不过电视机里重播的《还珠格格》来的火热,这一年我们 17 岁。 +△宋谨手机拍摄画面(4:3):程澈骑单车背影(看不清正脸) +宋谨:程澈,程澈,采访你一下,院里的人都说你爸在外有私生子了,真的假的? +程澈:滚开 +△程澈推开手机(4:3) +△夏日蝉鸣,一名少年手抱着篮球、一名少年举着手机,采访着一边骑着自行车的少年,红灯亮起,少年一脚撑地将自行车停在马路边 +宋谨:反应这么大,看来是真的 +△程澈黑色短发,穿着蓝白运动装,斜挎背着黑色斜挎包。他双臂撑在自行车扶手上,一条腿撑着地面,微风吹过头顶树叶沙沙作响。(背影,不交代程澈正脸) +△宋谨戴着白色鸭舌帽停在他旁边故意挪揄他。 +观鹤:听说还是个小姑娘,恭喜啊,喜提新妹妹! +△这时绿灯亮起,程澈不耐烦的骑车拐进巷子。 +宋谨(调侃):程澈,你骑这么快干什么,急着回家见妹妹吗? +1-2 场 黄昏 外 路边/家门口 +人物:程澈、宋谨、观鹤 +△同时黑色轿车行驶在柏油马路 +1-2A 昏 内 车内 +△车内,云想手里拿着 mp3,白色的耳机线穿过了她任凭风吹乱的头发。(耳机里播放着五月天的《知足》) +△云想看着窗外茂密大树发呆 +【此处有文案】【文案大意:夏天、她对未知的好奇跟担心】 +△落日余晖洒在黑色轿车,轿车最终穿过小巷停在家门口,出片名《好想你知道》 +△程枭(程澈父亲)给云想下车拿行李箱,云想背着书包下车 +程枭(走到她身边):想想,以后你就是程家的人了,别和我们客气,都是一家人。 +△晚风吹起云想的白色长裙,云想抬头看向天边落日,最后视线落在这栋楼前。 +云想 OS:以后,这会是我的‘家’。 +云想(微笑):嗯! +程枭:待会儿队里有事我得去一趟,你阿姨今晚医院夜班也不会回来,不过小澈会在 +云想:小澈是…… +△话还没说完,程枭看向巷子口。 +程枭:他回来了。 +△这时晚风吹起来,伴随着树叶作响的声音,云想顺着视线看过去 +△程澈骑着一辆黑白色越野自行车出现在视野中,夕阳透过树叶洒下斑驳光影投在少年身上。 +△晚风吹动程澈的发丝,棱角分明的侧脸被夕阳绘出金色的轮廓。 +△单车在云想面前停下 +△程枭热情的赶忙介绍。 +程枭:想想,这是我儿子小澈,小澈,这是云想,以后就是你妹妹了。 +△程澈皱眉打量着云想 +程枭:想想,以后你们会经常见面打交道,好好相处,我让小澈多照顾你。 +△云想笑着乖巧点头,主动友好伸出手。 +云想:你好,我…… +△话没说完,程澈直接冷脸骑车绕过她,然后把车丢到一边,进了家门。 +△云想的手停在半空,几秒后尴尬的收回来。 +程枭(尴尬):程澈你什么态度!!想想,别往心里去,他从小被我惯坏了,没礼貌。 +云想(强装微笑):没关系。 +1-3 场 夜 内 客厅 +人物:云想、程澈 +程枭 VO:也不知道你的口味变没变,晚饭我已经做好了,我跟你阿姨经常要上晚班的,你就 +先吃着,小澈…甭管他 +△云想走到餐桌前,孤伶伶的看着摆满了一桌子的饭菜。 +△云想缓缓坐下,刚提起筷子身后传来冷冰冰的声音。 +程澈:喂,你几岁了? +△云想慌忙转过头。 +△程澈双手抱在胸前,倚靠在门栏边。 +△上身穿着干净的白色 T 恤,一条白色毛巾挂在脖间,头发湿润还有水珠滴下,眼神透着杀气 +第二集: +2-1 场 日 内 客厅 +人物:云想、程澈、宋谨 VO、观鹤 VO +程澈:喂,你几岁了? +△云想慌忙起身站好,一脸乖巧 +云想:17 了。 +△程澈脖后隐约能看到藏起的耳机线,耳机里发出尖锐爆鸣 +宋谨 VO:我去!跟你同岁,都这么大了,难道就没人发现吗?这么刺激! +观鹤 VO:宋谨,我的耳朵坏了你得赔!小点声。 +宋谨 VO:哎哥们,新妹妹好看吗?乖吗? +△程澈皱眉快步到云想面前,两人离得很近,云想有些不知所措 +△程澈一言不发,云想被看的有些不自在,把脸瞥向一边,避开程澈的注视,身前的双手慌乱 +的攥紧 +△程澈发间的水珠滴下,刚好落到云想的手上 +△云想心里一搐,抬起头,迎上程澈的目光 +云想:你…好呀,有什么… +程澈(打断):为什么来我家? +云想:哦,来读书,借住在这儿。 +△云想身后投下一束舞台光,宋谨和观鹤站在中间(戏剧化展现) +△宋谨坐在沙发上,手里拿着游戏手柄,状态亢奋 +△观鹤戴着眼镜,手里捧着书端坐着,十分沉着 +宋谨:你还没回答我呢,新妹妹好看吗? +观鹤:这不是重点,你没听到她刚才说什么吗?来读书,意味着常住啊。 +宋谨:我靠!程澈,她该不会是来跟你分家产的吧?赶紧把她敢出去! +观鹤:嗯! +宋谨:所以…长得好看吗,嘿嘿 +△程澈不耐烦的把耳机摘了下来,场景恢复正常 +程澈:我爸都和你说了什么? +云想(思考):程叔叔也没说什么,大概是让我把他当爸爸,把这里当自己的家。 +程澈:(轻哼一声)程、叔、叔 +△云想一脸疑惑 +程澈:你也读六中是吗? +云想(心慌的点头):嗯。 +程澈:不管你跟我爸是什么关系,你听好。 +△云想被这种压迫感吓得下意识后退一步,吞咽口水盯着他看,大气不敢喘。 +程澈:在家不许靠近我,不许看我,在学校不许说认识我,我的任何东西不许碰! +△云想迅速抬起手,挡住自己的眼睛 +云想:好,听你的。 +△云想答应的很痛快,让程澈感到意外的挑挑眉 +云想 OS:划清界限也好,不然还要费尽脑汁想怎么打好关系。 +△过了半会儿云想偷偷露出一点指缝,发现程澈早已不见踪影 +△云想舒了口气把手放下,低头却发现一只阿拉斯加(“罐头”)正吐着大舌头看向自己 +△云想发出一声惊叫,紧接着就端起身后桌子上的菜,跳到了桌子上 +△客厅的大肚电视机里正好播放着《开心鬼》把狗变成人的桥段 +△这边罐头兴奋的围着桌子转圈,朝云想扑去 +云想(害怕):程…澈!你…是狗吗!? +第三集: +3-1 场 夜 内 客厅 +人物:云想、程澈 +△云想蜷缩在桌子上,罐头围着桌子打转 +云想:我保证不靠近你,也求求你,别靠近我! +程澈:你骂人可真… +△云想寻声望去,程澈正站在房门口 +云想(晃过神来,看了看两边):我还以为…对不起,能不能拜托你把这位…不是…这只… +程澈(打断):罐头,过来 +△罐头屁颠屁颠地跑到了程澈的身边 +△云想坐在桌子上,手里还举着两盘菜冲程澈尴尬的笑了笑 +云想(尴尬):吃…吃点吗? +△程澈白了眼,带着罐头进了房间,关上房门 +3-2 场 日 外 公交站台 +人物:云想、程澈 +△程澈坐在脚踏车上,一只脚踩在地面上支撑着,肩上斜跨着黑色的包 +△云想背着双肩包,小跑到程澈身边,没敢看程澈 +△程澈低头看旁边的云想,她也穿着校服,显得乖乖的。 +程澈:在这里坐 363 公交到沈城六中站下。 +云想(闷闷):嗯,谢谢。 +程澈:记住我昨天说的话。 +云想:嗯,我记得,在学校跟你保持距离,不认识你。 +△程澈说完就踩着自行车离开 +△云想直到程澈走远才敢转过身来,看着程澈远去的背影 +3-3 场 日 内 学校教室/走廊 +人物:云想、程澈、宋谨、观鹤、洛米、同学数名 +△程澈坐下,宋谨一屁股坐在程澈的桌子上,观鹤站在一旁。 +宋谨:待会你给我们指认一下,看看这个嚣张的私生女长啥样,咱们得给她来个下马威!最好 +把这个私生女赶出校园,保你狗命! +程澈(又被人叫成狗,皱眉):你才是狗,把你狗屁股从我桌上移开! +宋谨(调侃):哟,今天怎么火气这么大,果然,这个新妹妹是个狠角色! +观鹤:你别在这造谣拱火了,我觉得还是得先把事情弄清楚比较好。 +宋谨:要不这样,咱们装古惑仔 +镜头一转 +3-3A 夜 随意场景 +【戏剧化表达】 +宋谨扮陈浩南,后面站着程澈和观鹤,三人手拿滑轮打火机,步步逼近 +宋谨:铜锣湾程家只有一个儿子,是我大哥,程澈! +话音刚落,一本书将宋谨打出画 +3-3 日 内 学校教室/走廊 +宋谨抱着书捂着脑袋入画 +程澈:少看电视,看坏脑子。 +宋谨(捂脑袋):我认真的,我们必须得行动起来了阿澈!!看我怎么把这个私生女… … +△宋谨狠话还没说完,整个人就呆住了。 +宋谨:我的老天奶啊,这是谁?。 +△程澈寻着宋谨的视线望去,走廊中云想披着晨光走来。 +△云想和一旁的女生(洛米)说笑着,眼眸化成了月牙,格外明媚。 +△微风吹起云想的头发,荡漾在少年的心上。 +△程澈的目光也驻留在了云想身上。 +宋谨:居然还有我没见过的女同学,哪个班的啊。 +程澈:云想,你想把她赶出学校的人。 +△宋谨跟观鹤愣住。 +第四集: +4-1 场 日 内 学校教室 +人物:云想、程澈、宋谨、观鹤、洛米、同学数名 +△洛米带着云想走向讲台,教室里同学们的目光陆续被吸引过去 +同学 A:班长,这谁啊 +洛米:给大家介绍一下(一把搂住云想的肩膀)这是转到咱们班的新同学,云想 +△教室里掌声雷动,还夹杂着男同学的口哨声、欢呼声 +△云想微笑鞠躬,落落大方的介绍自己 +云想:大家好,我叫云想,是云想衣裳花想容的云想,接下来要和大家一起度过高三,希望大 +家多多关照… … +△讲台下宋谨观鹤围在程澈身边“说相声” +宋谨(感叹):要命喽(目不转睛)这是你妹妹?程澈你真狗啊!怪不得我问你长得怎么样你 +不回我,故意的吧。 +观鹤(笑):她配不配进程家。 +宋谨(目不转睛):她配!她绝配,顶配! +观鹤:分家产给不给? +宋谨:给!都给她!! +程澈:闭嘴 +△程澈说完便扑倒在课桌上 +△讲台上洛米还在介绍着云想 +洛米:据我所知,云想还是一名学霸。总之云想以后就是我好姐们儿,你们谁都不准欺负她啊 +同学 A(起哄):有班长罩着,我们谁敢啊 +宋谨:就是谁敢啊(看向程澈,阴阳怪气),再次欢迎云想同学! +△教室里再次想起掌声,宋谨鼓掌欢呼声很大。 +洛米:云想,你先坐那个位置吧,程澈同学旁边刚好空出一个位置 +△云想心头一紧,瞟了眼程澈所在的位置 +△程澈趴在桌子上,头埋在手臂里 +云想:要不还是… +教室外同学 VO:班长,沈老师让你去趟办公室 +洛米:好嘞!(转头看向云想)你先坐着,过几天我们会重新排座位,待会儿见。 +△云想尴尬的点点头,背着书包走过去,程澈没有抬头。 +△宋谨先热情的迎了上去 +宋谨:来,云想同学,坐这里。 +△宋谨引着云想坐到程澈身边的位置上,宋谨一脸痴汉样子托腮坐在前面椅子看着云想。 +宋谨:自我介绍一下,我叫宋谨 +云想:你好 +宋谨:不用这么拘束,我和阿澈是发小 +云想(假装不知道):哦!阿澈是? +△趴在一旁的程澈,手指微动,偷偷听着两人的对话 +宋谨:阿澈就是程澈 +云想:程澈…名字不错,谁啊? +△宋谨一愣,随后恍然大悟,悄悄凑到云想面前 +宋谨:我知道的,你是程澈的妹妹 +云想(尴尬笑笑):哈哈,这样啊 +宋谨:既然是程澈的妹妹,就是我的妹妹,妹妹,以后有事你跟哥哥开口,哥罩你! +云想:谢谢宋谨哥。 +△这一声宋谨哥,直接送宋谨上天。 +宋谨(娇羞):嘿嘿,不客气云想妹妹 +△程澈忍不了,突然踢了一脚桌子。 +宋谨:你有事儿啊? +△程澈坐直身子,瞪着宋谨,宋谨倒吸一口凉气 +程澈(冷漠的笑着):我没事儿,谨哥。 +宋谨(慌张):阿澈,你别这样,我害怕 +△程澈起身离开,宋谨追了出去。 +△剩下云想独自坐在座位上 +云想(小声嘀咕):我又招惹到他了?奇怪… … +第五集: +5-1 场 日 内 教学楼走廊/校园路上 +人物:云想、洛米、同学数名 +△下课铃声打响,洛米一只手拿着哇哈哈矿泉水,另一只手拉着云想正往操场的路上跑着。 +云想:洛米,我们这是要去哪儿。 +洛米:篮球场这会儿正精彩着呢,你哥也在里面。 +△云想愣住,停下脚步 +云想:我?我哥? +洛米:程澈啊。 +云想(错愕):你怎么知道…… +洛米:宋谨说的,他是个大嘴巴 +云想:啊…确实…但是我… +洛米(打断):快走快走 +△洛米再次拉起云想跑起来。 +5-2 场 日 外 操场 +人物:云想、程澈、洛米、宋谨、同学数名 +△操场上,程澈、宋谨,正在和其他同学打 3v3 篮球 +△附近零零散散围了不少人,小姑娘居多。 +△两人来到操场,恰好看到程澈投篮进去,全场发出惊呼。 +洛米(夸赞):漂亮!(推了推一旁的云想)帅吧?! +△云想的目光情不自禁地追随着程澈。 +△程澈大汗淋漓,发梢都湿了,撩起衣服擦了擦额头的汗珠,隐隐露出健硕的腹肌 +云想 OS:确实帅。 +△程澈忽然转过头,迎上了云想的双眸。 +△程澈歪歪脑袋,挑了下眉 +程澈 OS:你在看什么? +△云想不动声色地偏过头,躲避程澈的目光。 +△云想身后的女生在窃窃私语 +同学 A:“程澈在看谁?” +同学 B:“我们这个方向,该不会是在看你吧?” +同学 C:“程澈这个眼神,太撩了吧。” +△洛米用胳膊碰了碰云想,把一瓶水塞到云想手里 +洛米:想想,你去给程澈送水! +云想:啊?我不去。 +洛米:为什么?你俩同住屋檐下,不能一直老避着对方。 +云想:我过去就是找骂。 +洛米:程澈要是敢骂你,我撕烂他的嘴。 +△云想还想拒绝,结果被洛米一下推出去好几米,恰好跟迎面走来的程澈打了个照面。 +△云想抱着水转身就要走,紧接着是洛米的声音。 +洛米:想想!小心!! +△云想看过去,篮球正朝她的脸飞来。 +△云想来不及反应,只能认命闭上眼,手臂忽然被人拽了一下,她转身直接撞进那人怀中,整 +个人也转了个方向。 +△篮球砸在了程澈的背上。 +△随着球掉落的声音,紧接着场面安静,云想睁开眼看到自己被程澈抱在怀中,程澈的一只手 +抓着她的手臂,另一只手扶着她的后脑勺保护,程澈逆着光垂头看她,顿时周围全都安静了, +只能听见两人快而有力的心跳声。 +【此处有文案】【文案大意:关于少女的心动,源于一场“意外”】 +第六集: +6-1 场 日 外 操场 +人物:云想、程澈、洛米、宋谨、同学数名 +程澈:闯进来干什么? +云想:我… +△程澈松开手,不知道是热的还是害羞,云想的脸已经红了,程澈的耳朵也是红的,额头还有 +汗珠。 +△洛米有些自责的跑过来,如果不是她推云想,就不会发生这种事。 +洛米:想想,你没事吧? +△云想摇摇头,程澈有些责怪的看着她,宋谨走过来。 +宋谨:想想,你来送水的吗? +△云想低头看了眼自己的水瓶,点点头 +△天气很热,发丝黏在了云想的侧脸,锁骨汗珠感觉镀了一层细闪,白皙好看。 +宋谨:给谁的? +洛米:肯定不是给你的啊,明知故问。 +△云想抬头看程澈,程澈眉头都拧在一起,满脸写着生人勿近,她下意识后退一步把水递给宋 +谨。 +云想:给你的,宋谨哥。 +△说完云想就跑走了,洛米赶紧跟上去 +△宋谨拿着水愣住,随即满脸贱兮兮向程澈炫耀。 +宋谨:程澈,你妹妹给我送水。 +宋谨:程澈,你妹妹不会看上我了吧? +宋谨:程澈,你妹妹要是追我的话,我…… +△程澈一巴掌把宋谨“丑陋”的嘴脸推开 +程澈:你要点脸 +宋谨:怎么,你妹妹对我好,你吃醋了? +程澈:闭嘴!!你再多说一句话,我现在就让你后悔喝这瓶水。 +△宋谨识趣的闭嘴,程澈转身离开。 +6-2 场 昏 内 教室 +人物:云想、洛米、程澈 +△云想和洛米一前一后进了教室 +洛米(愧疚):想想,是我心急了,对不起,我只是想快点让你俩… +△云想突然转身,盯着洛米脖间五月天的项链,洛米征在原地 +云想:你是不是喜欢五月天 +洛米(摸了摸脖间的项链一脸懵):… 是… +△云想拎出自己的项链和洛米脖间的一模一样 +云想(开心):那我们就是朋友啦 +△洛米紧皱的眉头也终于舒展开来 +云想:朋友之间不用说对不起 +△云想洛米相视一笑 +△洛米也举起项链,两个相同的项链在空中摇摆 +【此处有文案】【文案大意:女孩之间的友谊,真的很简单】 +△洛米恢复大姐大的气质,一把搂住云想 +洛米:以后要是程澈欺负你,你就搬到我家来住,咱不受那委屈 +云想(微笑):好!我现在就是寄人篱下,给他留点面子而已,谁要天天盯着他那张臭脸… … +△两人欢笑着,突然一个冰冷的声音在她们身后响起 +程澈:云想 +△云想洛米慌乱的回头看向程澈 +程澈:看来我进来的不是时候 +第七集: +7-1 场 昏 内 教室 +人物:云想、洛米、程澈 +△洛米摊开手挡在云想身前。 +洛米:程澈,你有什么冲我来,而且这是在学校,你要是敢… +程澈(打断):云想,班主任叫你去办公室 +△说完程澈转身离开,留下洛米和云想尴尬的待在原地 +7-2 场 昏 内 教师办公室 +人物:云想、程澈、沈航宇 +△云想被叫到办公室,刚走进来就听到沈航宇在训斥程澈。 +沈航宇:你看你上学期期末考英语考了多少分!才二十分,不该错的都错了,这么马虎吗! +△沈航宇把试卷拍到桌子上,上面赫然写着二十。 +沈航宇(严肃):程澈,现在是高三,马上面临高考,你必须把学习态度拿出来!! +△云想后退一步想出去等他说完再进来,沈航宇抬头看到云想。 +沈航宇(叫住):哎,云想,过来。 +△程澈抬头看过去,云想站在门口。 +△云想走过去,沈航宇拿出入学申请表,上面是云想青涩的照片,程澈不自觉歪头看。 +沈航宇:在这上面签个字,然后把你的教科书领走 +△云想点头签上字,程澈看到紧急联系人上面写着他爸的手机号。 +程澈 OS:我爸的手机号在她联系人中,果然。 +沈航宇:程澈,把老师的话放在心上! +程澈:嗯,知道了。 +△云想把签好字的表递给沈航宇 +沈航宇:云想,你的书在门后,拿回去吧。 +云想:嗯,谢谢沈老师。 +△云想转身去搬书,书厚厚的一摞,很重,云想艰难的搬起来同时把她整个人都挡住了。 +△云想蹒跚着步伐往外走,顶部的书却往一边倒去,云想的身子也跟着往一边歪了过去。 +△眼看着已然倒下去,云想的身子却又一点点支撑了回来。 +△是程澈在一侧扶住了她。 +△程澈用自己的身子挡住了即将要掉下去的书。 +△程澈接过云想手中所有书,指尖触碰到云想的手(特写),云想抬头对上程澈看过来的目光。 +△程澈抱着书离开,云想快步跟上。 +7-3 场 昏 内 教学楼走廊 +人物:云想、程澈 +△两人并肩往前走,黄昏通过窗户照进来,整个走廊仿佛被拉长了一般,走不到尽头。 +云想:那个,谢谢。 +程澈(冷漠):别想太多,是因为沈老师在,不然她又要念我。 +云想:哦…那个…今天在篮球场,不好意思啊,我不是故意打破我们的规矩的。 +△云想快步跟着。 +程澈:道什么谦,你又没靠近我 +△程澈突然顿住脚步,看向云想 +程澈:水不是给了你宋谨哥了吗? +云想:啊? +程澈:你宋谨哥很开心。 +△说完程澈就搬着书拐进了教室,剩下一脸蒙圈的云想。 +第八集: +8-1 场 夜 内 客厅 +人物:云想、程澈、罐头(狗) +△深夜,云想在厨房倒水,回想着白天程澈的话 +云想 OS:他什么意思,难道是怪我没有给他送水? +△突然传来罐头的叫声,云想看过去,罐头也正兴奋的看着她 +云想(慌乱):你…冷静一点…乖 +△云想边说,边往后退,突然撞到了一堵湿湿热热的“墙” +△云想回头,程澈湿漉漉的头发,穿着短裤裸着上半身。 +△云想视线缓缓从程澈的脸移到他结实的小腹 +程澈:看够了吗? +△云想反应过来,她红着脸转身背对程澈 +△云想被“前后夹击”,在原地一动不敢动。 +云想(脸红):能不能让罐头进去,还有…… +程澈:还有什么? +云想:你也进去。 +程澈(故意打趣):进哪? +云想:进你房间,你俩一起… … +程澈 OS:她是怕狗还是怕我? +程澈:你在命令我? +云想:我不敢 +程澈:你挺敢的,你不用给我留面子 +云想 OS:白天的话还记着呢,小心眼… +云想:程澈,拜托…(突然想到什么,献殷情)对了,你英语是不是很不好? +程澈:什么? +云想:这不马上就要开学考了,我英语还不错,可以帮你补习… +程澈(轻哼一声):不用 +△罐头摇着尾巴朝她走过去,云想后退几步。 +云想:程澈! +△程澈不紧不慢的抱臂看她慌张模样。 +程澈:叫哥。 +云想(愣住):什么? +程澈:叫哥我就带罐头进去 +△云想看看罐头,咽口唾沫。 +云想:程澈哥。 +△程澈转身 +程澈:罐头,走。 +△罐头跟着程澈进了房间,云想才敢转过身来 +云想(小声嘀咕):干嘛忽然要我叫哥… +8-2 场 日 内 教室 +人物:云想、程澈、张大马 +△开学考,班级里的桌位全部被拉开。 +△黑板上醒目的写着“冷静沉着 细致认真”。 +△同学们都在认真的写着考卷。监考老师端着保温杯来回巡视 +张大马:英语考试还有最后 10 分钟,大家抓紧时间! +△云想微微侧头,发现程澈正趴在桌子上睡觉。 +云想 OS:难怪不用我帮他补习,他根本就不在乎,等成绩出来程叔叔又要生气了。 +△程澈翻身过来刚好瞟到云想。 +△云想叹气摇摇头,一脸惋惜。 +8-3 场 日 内 学校走廊 +人物:云想、程澈、洛米、同学数名 +△字幕:两天后。 +△洛米拉着吃阿尔卑斯棒棒糖的云想挤进人群看公告栏的成绩公布单。 +洛米:想想,走快点,咱们先看程澈的。 +△洛米往前头挤,云想往最后排看。 +云想(自言自语):为什么看程澈的?而且看他的不应该从后往前看吗? +△洛米挤来挤去终于在最前面看到程澈的名字,她兴奋的大喊。 +洛米:找到啦! +△云想看过去,赫然看到密密麻麻的成绩单中,程澈的名字在最前头第一名,她的棒棒糖掉落 +在地(特写) +洛米 VO: 我还以为你能比过他呢! +云想 OS:什么?!他是…第一名? +程澈 VO:继续加油啊,第二名。 +△云想猛的回头,程澈双手插在裤兜,笔挺的站在她的身后。 +△云想震惊的瞪大眼睛。 +云想 OS:不是,也没人告诉我,程澈是个学霸啊! +云想 OS:老师批评他交白卷,考试还睡觉,竟然考了个第一? +云想 OS:我大言不惭地要给他补习英语,结果自己考了个第二? +云想 OS:是谁考了个第二名还不识好歹要去给第一名补习? +云想 OS:啊!!太丢脸了!!(镜头快切垫独白) +△程澈被盯得有些不耐烦了,开口 +程澈(调侃):看呆了?小老师? +第九集: +9-1 场 日 外 学校阶梯 +人物:云想、洛米 +△两人坐在阶梯上,听着 MP3(里面播放着五月天的《听不到》)。 +△云想哀嚎一声倒在洛米肩上,洛米忍不住大笑。 +云想:洛米,别再笑话我了。 +洛米(大笑):想想,原来你对程澈有这么大误解,这么说吧,程澈一直是咱们学校的学神, +而且打小学习就好。学校的各项比赛,都是程澈代表参赛的。 +云想(纳闷):那期末考试他的成绩… +洛米:是因为他当时拉肚子,有几科没考。 +云想(恍然大悟):所以考英语的时候趴在那睡觉是因为对他来说太简单了? +洛米:嗯,写得太快,没法提前交卷。 +云想:我这次是真没脸见他了!! +△耳机里的音乐突然变得卡顿,传出刺耳的长音。 +云想:这是…怎么回事。 +△云想摘下耳机检查,发现 MP3 已经坏了 +9-2 场 日 内 学校教室 +人物:云想、程澈 +△云想走进教室,偷感极强的坐到程澈旁边。 +△云想眼巴巴看着程澈,程澈低头写着作业没有搭理。 +△云想用手指轻轻戳了戳程澈的手臂,程澈挪开手。 +程澈:小老师,你违规了。 +云想(微笑):之前都是我有眼不识泰山,你别往心里去哈。 +程澈(冷漠):哦。 +云想:那个…我们的规矩能不能先放一边? +程澈:有事儿? +云想:晚上放学,你可不可以跟我一起去家附近找个维修店,能修 MP3 的那种? +程澈:不去。 +△程澈果断拒绝,云想双手合十继续讨好。 +云想:我一个弱女子,又不认识路,晚上出去要是出了什么事,程叔叔一定会怪你的。 +程澈(依旧低着头):你?弱女子?没看出来,怪就怪吧。 +云想:我保证,就麻烦你这一次! +△程澈依旧低着头,没松口。 +△云想想到昨晚他忽然让自己叫哥,心中冒出一计。 +△云想趴在桌边,轻晃着程澈的手腕,小可怜地叫着 +云想:程澈哥哥~~ +△程澈写着题的手狠狠一顿,然后握紧了手中的笔。 +△他抬了抬睫毛,正对视上云想那张可怜兮兮的模样。 +△她趴在他的桌边,可爱的要死。 +△程澈捏着的笔的手逐渐用力,似乎心底莫名跳乱了一拍。 +△程澈甩开手,没说话,迅速起身走出了教室 +云想:程澈,你油盐不进呐!不去就不去!我自己也可以! +△教室外,在云想看不到地方 +△程澈倚靠在墙上,手扶了扶刚才被云想握住的地方,偷偷红了脸 +【此处有文案】【文案大意:少年就像一首需要翻译而炽热的诗。他们宁愿将心事告诉和煦 +的风…】 +9-3 场 夜 内 维修店 +人物:云想、维修店老板、程澈 +△云想给老板递过 MP3 +云想:老板,能修好吗 +老板:小问题,马上好 +△镜头拉开,程澈默默守在门外 +【此处有文案】【文案大意:把秘密藏在每个睡不着的夜晚里,偏偏不愿意口直心快说一句: +我在意】 +9-4 场 夜 外 路边 +人物:云想、程澈、卖花的小朋友 +△云想戴着修好的 MP3 开心的走在前面,程澈在后面默默跟着 +△突然一个提着花篮的小朋友拽住了程澈 +小朋友:哥哥买朵花吧 +△程澈一愣,摆了摆手 +程澈:不用了,谢谢 +△程澈再一抬头,已经不见云想的踪影 +9-5 场 夜 外 巷子 +人物:云想、黄毛青年、程澈 +△云想兜兜转转,拐到人很少的巷子口。 +云想:我记得回去的路是往这边啊 +△身后突然有人撞了云想,云想警惕回头,一名满身酒气的社会青年色迷迷看她。 +黄毛青年:哟,同学,你六中的呀?一起,去喝、喝两杯? +第十集: +10-1 场 夜 外 巷子 +人物:云想、黄毛青年、程澈 +△云想还穿着校服背着书包,显然一副乖乖女任人宰割的模样,她警惕后退几步。 +△黄毛青年逼近,黄毛抓住云想的手腕。 +黄毛青年:想跑?跑什么啊?!没听到老子跟你说话吗?你他妈耳朵聋了!? +云想:放开! +黄毛青年:哟,还是个性挺烈的小野猫。 +△黄毛青年一把将云想拽进怀里。 +黄毛青年:乖乖听话,你晓得我是谁吗?你在这块打听打听。 +△云想另一只手握拳(特写),打算做反抗,突然一个声音响起。 +程澈 VO:说来听听? +黄毛青年:谁啊! +程澈 VO:你爹! +△人没到声音跟拳头先到,程澈飞身直接踹到黄毛青年的侧腰,黄毛青年被踹到墙上。 +云想:程澈… +△程澈拉起云想的手,往巷子外走去。 +程澈:走。 +△黄毛青年气不打一处来,从身后掏出一把匕首(小刀) +黄毛青年:在妹子面前装英雄,你会后悔的! +△程澈和云想停下,程澈把自己书包递给云想。 +程澈:你害怕,就先跑。 +△说完,程澈如同“英雄一般”独自走向持刀的黄毛青年。 +△云想感到有安全感的紧紧抱着他的书包,随后缓缓转身看向程澈。 +△程澈正与持刀的黄毛青年对峙。 +黄毛青年:今天老子要给你点颜色瞧瞧! +程澈:喝点马尿找不到东南西北了,也就欺负欺负小姑娘的本事。 +△程澈,反击。 +10-2 场 夜 内 公交车 +人物:云想、程澈、乘客 +△特写手机,诺基亚屏幕里放着《紫禁之巅》不要再打啦片段,镜头拉远带出坐在后排的云想 +程澈 +△两人端坐在一排,程澈看向窗外没有说话。 +云想:谢…谢谢… +程澈:哦。 +云想:程澈,你该不会是一直在跟着我吧… +程澈(打断):路过,刚好路过 +云想:那也太巧了,不过你刚才真的超帅,就像电视剧男主角一样。你是我见过最厉害的人, +成绩好、身手好、长得还标志… +程澈(被夸的有点不自在):假死了 +云想:怎么会呢,我特真诚 +△程澈没有理会,继续看着窗外 +△一个白色的耳机塞进程澈的耳朵,音乐顿时响起 +△音乐:五月天-《纯真》“长长的路我想我们是朋友,如果有期待我想最好是不说,你总是 +微笑的你总是不开口……”。 +△程澈回过头,刚好迎上云想期待的目光。 +云想:怎么样,虽然用了很久了,但音质还不错吧。 +程澈:比学校广播站还差,赶紧换一个吧。 +云想(摇头):不换。 +程澈:很重要吗? +云想:嗯,很重要。所以我是真心的谢谢你,程澈。 +△程澈耳朵瞬间红了,一时不知怎么回答。 +△突然一个急刹,云想往一旁倒去,程澈下意识接住。 +△耳机也跟着被扯下,在空中激烈晃荡。 +△而此时云想已经倒在程澈怀里。 +△云想一手拽住程澈手臂上的校服,一手勾住程澈的脖子,脸埋在了程澈的胸口。 +△程澈红透了脸,低头偷偷看云想,刚好云想抬头也看他,两人视线相撞。 +10-3 场 夜 外 公交路口 +人物:云想、程澈、程枭、胡楠(程澈妈妈) +△公交车紧急刹车在站牌停下,程枭跟胡楠买完菜拎着路过站牌。 +△程枭抬头看到车窗内的人。 +程枭(感叹):现在的年轻人真是… +胡楠:那孩儿怎么看着像咱家阿澈啊 +△程枭抬起手看了看手表 +程枭:嗯,这个点的确放学了。 +△胡楠用胳膊肘碰了碰程枭。 +胡楠(皱眉):哎旁边跟小澈一起的女孩是想想吗? +△程枭看过去,从严肃的表情转为震惊。 +△透过车窗可以看到云想跟程澈近距离对视,氛围满满。 +【一卡卡点】 +第十一集: +11-1 场 夜 内 公交车 +人物:云想、程澈、程枭、胡楠 +△程澈不自然的移开视线看向窗外,恰好看到自己爸妈看着自己,整个人一愣。 +△程澈离开跟云想拉开距离。 +△云想红着脸看向车窗外,她也有些害羞发懵的朝程枭跟胡楠礼貌打招呼。 +11-2 场 夜 内 客厅 +人物:云想、程澈、程枭、胡楠 +△大肚电视机里播放着《家有儿女》 +△云想程澈两人拘谨的坐在餐桌前,对面程枭举着报纸,时不时偷瞄两人 +△这是云想第一次跟程家全家人一起吃饭。 +△胡楠端着一盘菜放到餐桌上 +胡楠:老枭,你之前还说两小孩不对付,我这不看着挺好的吗 +程枭(放下报纸):嗯…吃饭吧。 +△云想不自然的拿起碗筷 +胡楠:想想啊,这两天住的还习惯吗?阿姨这几天医院比较忙,一直在加班,没能回来。 +云想(乖巧):没关系阿姨,住的挺习惯的。 +胡楠:那就行,多吃点,你太瘦了。 +△胡楠不断的给云想夹菜。 +△程澈刚吃了一口菜,震惊的抬头看胡楠。 +程澈 OS:我妈这么大度,一点不介意云想的身份。 +△胡楠看了一眼程澈,又看向云想。 +胡楠(笑):哎呀这孩子我越看越喜欢,长得真漂亮,要是跟我们家小澈定个娃娃亲的话。 +程澈(打断):妈,这怎么能乱说 +胡楠(打断):这有什么不能说的,想想这么漂亮,以后看上的男孩子有福啦。 +△云想害羞低头。 +胡楠:想想啊,谈了男朋友可得让你阿姨我把把关哦。 +程枭:差不多得了,别当着孩子面讲这些 +胡楠:有你什么事儿,吃你的饭。 +△程枭给胡楠夹菜。 +程枭:你也是,少说话多吃饭。(看向云想)想想别跟你阿姨学,说话没分寸 +△云想乖乖地点头 +胡楠:老枭,你这话我就不爱听了… +△云想看着程枭胡楠两人老夫老妻拌嘴的样子,想起了自己的爸妈,表情落寞。 +△程澈看向云想,似乎也注意到了云想情绪的变化。 +11-3 场 夜 内 卧室 +人物:云想、云爸 VO、云妈 VO +△云想打开 MP3,里面是她爸爸给她的留言。 +云想:幸好里面的东西没丢。 +△云想打开,云爸云妈慈祥的声音响起。 +云爸 VO:想想,有没有按时吃饭呀,等爸爸出完任务回来,给你带树莓蛋糕。 +云妈 VO:怎么又给想想带蛋糕,对牙齿不好 +云爸 VO:我们家想想这次考试又是第一名,好好奖励一下怎么了。 +云妈 VO:行行行,你就惯着她吧 +云爸 VO:咱就这么一个女儿,就得惯着。想想,等周末你妈妈有空了,咱们一家三口去游乐 +园玩! +△镜头拉远,屋内灯光昏暗很温馨,云想默默擦着眼泪哭泣。 +△云想躺在床上,眼泪划过脸颊,她默默听着 MP3 里面的声音。 +云想:爸,妈……我好想你们。 +第十二集: +12-1A 日 内 办公室 +人物:沈航宇,云想 +△沈航宇手里拿着云想的 MP3,一脸严肃,云想站在一旁低着头 +沈航宇:云想同学,在校期间是不能使用电子设备的,你成绩优异更要起到带头作用,这个老 +师先帮你保管了,放学后再来找我拿 +△云想乖乖点头一脸委屈 +12-1 场 日 内 教室 +人物:云想、程澈、洛米、宋谨、同学 3-4 人 +△课间,云想趴在桌子上闷闷不乐,洛米在一旁安慰 +洛米:想想,她能还给你已经很幸运啦,换做其他人,老沈早就… +△洛米边说边抬起手,做出准备打人的动作 +云想:哎 只是以后在学校再也听不到五月天的歌了 +△宋谨一脸兴奋的跑过来 +宋谨:惊天爆炸消息 +洛米:有屁快放 +宋谨:我们广播站换人了!你们猜是谁? +洛米:没兴趣,不想猜 +宋谨(撒娇):猜一下~猜一下嘛~ +△宋谨一脸神秘的看向云想,云想这会儿还头靠在桌上闷闷不乐。 +洛米:怎么?是云想啊 +宋谨:啧,当然不是!是她哥。 +洛米(震惊):程澈?不可能。 +△云想立刻坐直 +云想:啊?我其实跟程澈…… +△云想想解释,洛米震惊的大喊被打断。 +洛米:他有那闲工夫?还能瞧的上广播站?绝对不可能,你就吹吧! +△这时广播站开始播放,响起程澈低沉声音。 +程澈 VO:大家好,我是高三六班程澈,从今天开始就由我负责广播站,欢迎各位投稿,点歌。 +△程澈声音响起的同时,教室内大家齐刷刷看向小喇叭。 +同学 A:我去,竟然是程澈。 +同学 B:他怎么去广播站了,声音好好听啊 +洛米(起哄):程澈这小子可以啊!顿时来劲了!让我们愉快的一起刷题吧! +宋谨:哎哎,婉拒了哈米姐。 +△洛米跟宋谨打趣的同时,云想安静的听着程澈的广播开始做试卷。 +程澈 VO:接下来是广播音乐时间,祝大家有个充实美好的一天。 +△音乐:五月天-《纯真》“长长的路我想我们是朋友,如果有期待我想最好是不说,你总是 +微笑的你总是不开口……”。 +△还在做试卷的云想抬起头来感到震惊。 +【插入闪回】 +12-2 场 夜 内 公交车 +人物:云想、程澈 +△两人安静的插着同一个耳机坐在公交车听音乐。 +△公交车摇晃,云想一手拽住程澈手臂上的校服,一手勾住程澈的脖子,脸埋在了程澈的胸口, +几秒后两人同时抬头,视线相撞。 +【闪回结束】 +12-3 场 日 内 教室 +人物:云想、程澈、洛米 +△云想回过神来,她甩了甩脑袋打起精神。 +云想 OS:我在想什么!!做题做题! +△云想端正坐姿开始做试卷,时间过度 +12-3A 日 内 广播站 +程澈:今天的广播到这里结束了,祝大家有个愉快的周三,明天见。 +12-3 场 日 内 教室 +△云想正在做试卷,转着手里的笔,她甜甜的笑起来。 +云想(自言自语):明天见。 +△洛米听到云想的声音,八卦的回头。 +洛米:想想,你还挺配合的嘛。 +云想:什么?哦我很喜欢听学校广播站放的歌啦,感觉不同,所以期待一下明天见啦。 +洛米(笑):小姑娘,嘴硬的嘞。 +△洛米笑着回过头去继续做题。 +12-4 场 夜 外 教学楼走廊 +△时间过渡,空镜。晚上教学楼下课铃声响起,走廊同学们纷纷离开。 +12-5 场 夜 内 客厅 +人物:云想、程澈、程枭、黄毛父亲、黄毛青年 +△云想拿着 MP3 高兴的走回家,还没进门口听到里面的动静。 +黄毛父亲 VO:你儿子打了我儿子,这事老程你说怎么办吧! +△云想皱眉走过去看到黄毛青年脸上跟胳膊缠着绷带,他父亲指着程枭说话。 +程枭:这个年纪的孩子打打架不是很正常嘛,你别生气,程澈错了就是错了,我不包庇他。 +程澈!过来道歉! +△程澈靠在门边没动作。 +程澈(讽刺):要不要我给他跪下道歉啊? +第十三集: +13-1 场 夜 内 客厅 +人物:云想、程澈、程枭、黄毛父亲、黄毛青年 +黄毛父亲:你这臭小子,什么态度!程枭,就你儿子这德性,你现在不管教早晚会出事!这次 +就是我们家大度不追究,如果追究到底,你儿子非得进局子不可,到时候留下案底,哼,我看 +你们怎么办! +△黄毛父亲气冲冲丢下狠话离开,云想走进来刚好跟他擦肩而过,他上下打量云想。 +黄毛父亲:一家子都是什么人啊,小姑娘也没个小姑娘样子,这么小就知道勾搭男人了! +△程澈原本懒洋洋的满不在乎,他听到这句话站直身子准备冲上去。 +△程枭看到喊住他以免再惹事。 +程枭:程澈,过来跪下! +△程澈没说话,走过去背对云想跪在程枭面前,动作很干脆。 +△程澈的背挺得很直,脸上有着一股子倔强不屈服的劲儿。 +△程枭随手拿了茶几上的鸡毛掸子边说边重重抽在程澈背上。 +程枭(愤怒):我跟你说过多少次,不许打架不许打架!非得人家找到家里来是吗?!下次是 +不是真想进局子??你什么时候听过我的话!! +△程澈的身体一动不动,一声不吭,双手握拳。 +△云想惊呆了连忙走过去想解释,程枭不给她机会。 +程枭:想想,你回卧室,这是我们程家的家规,犯了错就要挨罚。 +△程枭挥起鸡毛掸子还要打下去,云想挡在前面跪下。 +△程澈震惊愣住,他看着云想坚定倔强的小脸。 +云想(着急):程叔叔,程澈打架是不对,但他是因为我才打的,如果要罚就一起。 +程枭(震惊):什么? +云想:上一次我去拿 MP3 的路上碰到他儿子,当时他们好像喝了很多酒,非要拉着我去喝酒, +是程澈帮了我。 +△程枭温柔的把云想搀扶起来。 +程枭:还有这事?!程叔叔去给你讨个说法。 +云想(点头):嗯嗯,不是程澈的错。 +△程枭看向程澈,语气还是很严肃冷漠。 +程枭:程澈,起来吧。 +△程澈没有动作,握着拳不肯动。 +程枭(呵斥):起来! +△云想怕事情变坏,她过去要搀扶程澈,程澈自己在这时站起来,程枭还没来得及说话,手机 +响起。 +程枭:队里有事,我先过去看看。 +云想:好,程叔叔您忙。 +△程枭离开,场面一度降到冰点,程澈准备回房间,云想拉住他的衣角叫住他。 +云想:程澈,谢谢你 +△程澈看着云想拉自己的衣角,云想反应过来迅速松开。 +云想:四不规则,我知道…今天叔叔阿姨估计都不会早回来,我请你去吃饭吧 +△程澈踟躇了会,没说话,随后走进房间,关上了房门 +△云想独自留在客厅,一脸愧疚 +第十四集: +14-1 场 夜 内 客厅 +人物:云想、程澈 +△云想呆站在客厅 +云想:他非要我愧疚吗,不想吃就说嘛,真是的。 +此时程澈的房门突然打开,程澈换了身衣服。 +程澈:喂,不是要请我吃饭吗?我换了身衣服,走吧 +△云想欣喜看着程澈 +云想(高兴):程澈!走吧,你想吃什么? +△程澈往外走着,云想跟出去, 镜头拉远。 +程澈:吃什么都行?嗯……海鲜、烧烤、炒菜,还有…… +云想:等等,你吃得了嘛。 +△两人并肩走远,声音渐渐消失。 +14-2 场 夜 外 巷子 +人物:云想、程澈 +△两人饭后并肩走在路上,程澈显然还是不开心,云想偷偷看他。 +云想:程澈。 +程澈(淡淡):嗯? +云想:吃饱了吗? +程澈:嗯 +云想:那你怎么还不开心? +△程澈没回应,云想笑着缓解气氛。 +云想:程叔叔罚你的事情,你不要放在心上哦。 +程澈:嗯。 +云想(笑):俗话说的好,男儿膝下有黄金,今日跪过天地和四方神明,以后定会万事顺遂! +程澈(疑惑):什么? +△云想神秘的绕着程澈走了一圈,古灵精怪的朝他身边空气弹了弹,样子滑稽又可爱,然后倒 +退走了两步路,程澈原本乌云密布的脸被她动作逗的嘴角微微上扬然后迅速收回。 +程澈:你还信这个啊。 +云想:信啊。 +△云想见程澈高兴,她自己也开心的像个小兔子一样在路上蹦跳,晚风吹过夹杂凉意,树叶沙 +沙作响。 +云想(神秘):你听。 +程澈(疑惑):听什么? +云想:夏天的声音。 +△程澈没听懂她的意思,但跟着安静下来听树叶被风吹的声音,他看着云想开朗活泼笑容甜甜 +的模样,心里也犯起阵阵回响。 +△云想闭着眼睛,认真的听着 +△程澈也不自觉的闭上了双眼 +程澈 OS:嗯…是夏天的声音 +△云想正闭着眼,突然被程澈抓住转身将云想抵在墙上用身体挡住。 +△云想被突如其来的动作惊到。 +△黄毛青年还带着几个“兄弟”从两人身边走过。 +黄毛青年:真他妈倒霉,今天一把都没赢! +寸头青年:哎,你看 +△云想抬头,程澈一只手抵在墙上,另一只手放在她的肩膀上,将她挡的很严实,他低头靠近 +云想脖子,温热呼吸洒在脖颈间,云想身体僵住不敢动。 +黄毛青年:哟还在大街上就把持不住了,谈的起女朋友开不起房间啊! +寸头青年:现在的女人可真不值钱 +△程澈近距离靠近让云想心脏都快跳出来了,她红着脸想动,程澈低声提醒。 +程澈:别动。 +△云想动的时候不小心碰到程澈后背,程澈没说话,但扶着她肩膀的手臂抖了一下。 +△程澈用扶着肩膀的手压上云想的后脑勺,将云想整个摁进自己怀里保护着。 +黄毛青年:快走吧,哥几个还等着咱呢 +△黄毛青年走远,程澈回头看了一眼确保他们离开才放开云想,云想已经脸红的呼吸都变快起 +来。 +云想:是谁? +程澈:之前和你搭讪的人,先回家吧。 +云想:好。 +14-3 场 夜 内 客厅 +人物:云想、程澈 +△两人回家,云想拘谨的跟在后面想说什么。 +云想:程澈,你等会有事吗? +程澈(转头):怎么了? +云想:那……你等会换个方便的衣服到客厅,我在客厅等你。 +△程澈上楼梯的动作停住,他不敢相信的回头看云想。 +△程澈暗暗握拳看着云想。 +程澈(严肃):云想,我程澈是正经人。 +第十五集: +15-1 场 夜 内 客厅 +人物:云想、程澈、罐头 +△镜切,电视里播放着《下一站,幸福》男主要求女主脱衣服片段 +△程澈穿着黑色背心下来,站在沙发旁边,两人有些尴尬。 +△云想赶紧拿起遥控器,关掉电视。 +云想:开…开始吧 +△程澈站在一旁一动不动 +云想:呃,你,过来,坐下! +程澈:你在训狗? +云想:我,没有,你不坐下我怎么帮你处理伤口。 +△程澈在沙发坐下,两人对视有些尴尬。 +△云想从医药箱拿出药膏,伸手比划了一下不知道怎么下手。 +云想:就,你,那个,你把衣服卷起来,我看看你的伤。 +△程澈默不作声转身把衣服卷起来,云想看到他后背是两条发紫的痕迹,已经破皮。 +云想 OS:这得多疼啊,夏天本来穿的就少……程叔叔下手真重。 +△云想感觉鼻头酸酸的,不自觉的红了眼眶 +△云想扭头开始摸黑给他擦药膏,手指触碰到程澈的后背,程澈手搭在沙发背上抖了一下。 +云想:等下可能会很疼,疼的话你叫出来。 +程澈:我…… +△云想小心翼翼的给程澈擦着药 +【此处有文案】【文案大意:我总是被保护的最好的那个,可被保护的人却也总是内疚的,所 +以我不想成为身后的那个人,我想独当一面,成为和你并肩的那个人,我想你知道…】 +△云想的泪珠夺眶而出,滴在了程澈的背上 +△程澈背上感觉一阵湿热,一愣,刚想说点什么又很默契的止住了 +程澈:你…(止住)涂好了吗 +云想:嗯… +△最后云想擦完药,程澈缓缓把衣服放下来。 +云想:这两天尽量别沾水。 +程澈:知道了。 +15-2 场 夜 内 卧室 +人物:程澈、程枭 +【此处有文案】【文案大意:在被保护这件事上,程澈也何尝不是那个被保护的人呢,只不过 +他的骑士是个嘴硬心软的人】 +△程澈躺在床上睡觉,门被轻轻推开,程枭走进来。 +△程枭走过去想查看程澈后背的伤,走过去看到椅背上扔着程澈下午穿的衣服,里面有一些血 +迹。 +△程枭感到难受又带着歉意的看向程澈。 +△程枭走过去轻轻帮他整理被角盖好,然后转身离开,走到一半发现衣服扔在地上,程枭轻轻 +捡起来叠好放在程澈床上,关门离开。 +△关门后,程澈睁开眼。 +第十六集: +16-1 场 日 内 客厅 +人物:云想、程澈、胡楠 +△第二天清晨,程澈从楼上下来看到胡楠端着白糖跟油条走过来。 +程澈:妈,这油条和白糖是? +胡楠:给想想准备的。 +程澈:云想的味觉嗅觉应该都很正常,谁家正常人吃油条沾白糖,她……。 +△程澈指着云想的门口话没说完,云想走出来坐下,笑的甜甜的。 +云想:谢谢阿姨,那我开动啦。 +胡楠(温柔):好,慢慢吃。 +△程澈指着的手还没放下,整个人目瞪口呆的看云想油条沾白糖吃的欢快。 +△云想看到程澈指着自己,慷慨的把白糖推过去。 +云想:你要不要尝尝? +程澈(摇头):你为什么这么爱吃甜的? +云想:吃甜的会让人很开心呀,你真的不试试吗? +程澈:不用了,你慢慢享用。 +△程澈在她对面坐下喝牛奶吃油条。 +△胡楠端着炸好的糖饼走出来。 +胡楠:我新做的糖饼,想想你尝尝。 +△云想吃了一口,惊讶的竖起大拇指。 +云想:阿姨你好厉害,怎么会有人长得这么漂亮,做饭也好吃! +胡楠(开心):真的吗?你喜欢吃阿姨以后每天都做给你吃好不好? +△程澈正在喝牛奶,被两人的对话呛到。 +胡楠:慢点喝(边离开边说)哎,还是女儿好呀。 +△胡楠故意挪揄程澈,看过去,程澈撇撇嘴故意一口气喝完牛奶放下空杯子,胡楠忍笑。 +16-2 场 日 外 巷子 +人物:云想、程澈、宋谨 +△程澈推着自行车出来,路口宋谨早就骑着车在等他了。 +宋谨:早啊,妹妹呢? +程澈:某人一口一个妹妹,她是你妹妹,那我算什么? +宋谨:算喜之郎果冻,多点关心多点爱。 +△宋谨说完不忘贱兮兮的伸手给他比心,程澈满脸嫌弃。 +程澈:滚。 +△两人推着车已经走了一段路,云想才从门口急匆匆跑出来。 +△云想看着前面跟她拉远距离的两人,她努力小跑跟上去,却听到两人聊天。 +程澈:你这个嘴就是大漏勺,以后别在学校总把我跟她放在一起说,什么妹妹哥哥的,我宁愿 +不跟她有关系。 +△云想听到这句话渐渐停下,站在原地看着两人骑上车离开的背影心里失落。 +第十七集: +17-1 场 日 内 学校教室 +人物:云想、程澈、宋谨、洛米 +△07 快男超女实事画面混剪。【旁白大意:快男超女风靡一时,音乐潮流也来到了校园】 +△云想正在看书,洛米跑了过来。 +洛米:想想,听说下周一要办我最响亮音乐会,每班都可以派出代表上台表演! +云想:高三的也可以参加吗 +洛米:嗯!想想你要不要去唱一个 +云想:我听听还行,唱就算了吧 +△宋谨拿着 AD 钙奶走过来。 +宋谨:想想,做题呢,喏,给你的。 +△宋谨把 AD 钙奶递给云想。 +云想(高兴):谢谢宋谨哥。 +洛米:我的呢? +宋谨:你,下次 +洛米:滚 +△宋谨狗里狗气的跑到程澈对面 +宋谨:阿澈,我有事找你。 +程澈(冷漠):说。 +宋谨:阿澈,澈哥,哥,观鹤说求你了,音乐会你上台演一个。 +△云想听到,她从书中抬头看过去。 +云想 OS:程澈?他还会唱歌啊 +程澈(冷漠):他自己怎么不来求我? +宋谨:他忙着音乐会的事情呢,实在抽不出空来,这不是派小弟我来嘛。 +程澈:不感兴趣。 +宋谨(着急):程澈,阿澈,小澈澈,好哥哥~ +程澈:滚远点骚去 +宋谨(举手投降):好好,我走就是了,唉。 +△宋谨走之前给旁边看戏的云想使眼色,云想立刻明白。 +17-2 场 日 内 教室走廊 +人物:云想、宋谨 +△宋谨在走廊等云想,云想喝着 AD 钙奶走过去。 +云想:怎么了宋谨哥? +宋谨:牛奶好喝嘛? +云想:嗯嗯,好喝。 +宋谨:帮哥一个忙? +云想:原来是想找我办事啊,宋谨哥,你看这个牛奶我就喝了一口,要不…… +△云想想把牛奶还给宋谨。 +宋谨:你喝都喝了! +云想(叹气):好吧,吃人嘴短,说吧,什么事? +宋谨:想想,好妹妹,你劝劝你哥,上台演一个,我是带着任务来的,完不成观鹤会杀了我。 +云想(为难):我可能不行。 +宋谨:不!你行,你非常行!你行你上!求求你了。 +云想:可是。 +宋谨(着急):好妹妹,条件你开!哥给你把各种口味的糖果奶茶买来。 +云想:那我……试试,零食就不用了,宋谨哥,你能帮我找个家附近的周末兼职吗? +宋谨(好奇):你缺钱啦? +云想:没有,就是周末不想闲着。 +△宋谨想了想,答应下来。 +宋谨:好!交给我! +△宋谨从背后拿出一袋子零食,云想看到眼睛都亮了。 +宋谨(慷慨):不能为难我妹妹,拿着! +云想(开心):谢谢宋谨哥! +△走廊另一侧,程澈看到云想跟宋谨笑着说了什么,然后欢快击掌,他表情不悦的把书合上。 +第十八集: +18-1 场 夜 外 公交站牌 +人物:云想、程澈 +△放学回家的路上,程澈推着自行车,云想跟在他后面。 +云想:程澈,音乐会你真的不打算参加吗? +程澈:你跟你宋谨哥达成了什么某种交易?想出卖我? +云想:没有!绝对没有,我们对你绝对忠诚,我发誓! +△云想伸出两根手指发誓,程澈看了一眼。 +程澈:哪有发誓用两根手指的,麻烦你有点诚意。 +云想:程澈,你如果不答应的话回头观鹤肯定还找你,你要拒绝你的好兄弟吗?你答应他跟我 +答应一样嘛,就当卖我个人情。 +程澈:拒绝。 +云想(讨好):程澈,你声音好听,选歌有品,迷妹又多,长得也帅…… +△话没说完,程澈打断。 +程澈:别夸,我不表演 +云想:我的建议是,你表演。 +程澈(冷笑):谢谢,但我不听。 +云想(语重心长):程澈,听劝。 +程澈(同语重心长):云想,我从小就叛逆。 +程澈:拐个弯就到家了,今晚有红烧肉,先走一步! +△程澈随便找借口骑上车离开。 +△云想气的直跺脚。 +云想(自言自语):怪不得算命的说我十七岁有个坎儿,原来坎儿在这! +云想(小跑):哎,你等等我。 +18-2 场 夜 内 客厅 +人物:云想、程澈 +△餐桌上,云想依旧不放弃,不断逼近 +云想:哎呀,你就表演一个节目嘛。你自己好朋友操办的音乐会,你不表演,这合理吗? +程澈:合理。还有离我远一点 +云想:我是病毒吗?靠你太近会毒死你吗?算我求求你了坎儿哥,哦,不是,程澈哥。 +程澈(警惕):坎儿哥是谁? +云想(心虚):就……就以前学校玩的比较好的一个男同学啦。 +程澈:哦 +云想(心虚):我,我去拿碗筷。 +△云想溜走,过了一会拿着碗筷走过来,程澈站起来伸手要碗盛饭,云想一激灵缩回去。 +程澈:你干什么? +云想:你不是不让我靠你太近吗? +△程澈从她手里拿过碗盛饭。 +程澈:吃饭不算。 +△程澈盛好饭递过去给云想。 +云想:谢谢程澈哥哥,你最好啦。 +程澈:有你坎儿哥好吗? +△云想双手捧脸看着程澈,一脸狗腿样。 +云想:怎么会呢,程澈哥哥最好了,坎儿哥不好,他无情冷漠又自私,我求他什么,他从来都 +不会答应,但是程澈哥哥不一样了,对吧? +△程澈盛好自己的饭坐下,拿着筷子轻轻敲她的头。 +程澈:吃你的饭。 +△云想乖乖应了一声开始吃饭,程澈不动声色的低头笑了笑。 +18-3 场 日 内 教室 +人物:云想、洛米 +△洛米激动的抓着云想晃来晃去。 +云想:米,米姐,有,有点晕。 +洛米(激动):咳不好意思啊,我太激动啦,想想,程澈代表咱们六班报名音乐会啦! +云想:什么?!真的? +第十九集: +19-1 场 日 内 教室 +人物:云想、程澈、宋谨、洛米 +△程澈回来,云想凑过去。 +云想:这个人情你卖给我了? +程澈:别自恋,观鹤找我了。 +云想:好吧,你打算唱什么歌? +程澈:你想听什么? +△云想还真认真思考了一下。 +云想:我听什么你就唱吗,那我听…… +程澈(打断):当然不是。 +云想:那你问我干什么!幼稚. +程澈:逗小孩挺好玩的。 +云想:喂!! +△宋谨从外面进来,乐呵的凑过来。 +宋谨:你们聊什么呢。 +云想(笑):宋谨哥。 +△程澈看着云想甜甜的微笑,表情不悦。 +宋谨:乖,给你糖吃。 +宋谨:程澈,这几天好好排练哦,音乐会展现你的天籁歌喉。 +△宋谨把糖递给云想,语重心长拍了拍程澈。 +宋谨:那周末我找你哦。 +云想:好,谢谢宋谨哥。 +程澈(疑惑):你们到底瞒着我进行了什么交易? +宋谨:我和妹妹的小秘密,不告诉你。 +△程澈抬腿就要踹他,腿还没抬起来,宋谨跑走。 +19-2 场 日 外 咖啡店门口 +人物:云想、宋谨 +△从咖啡店出来,宋谨送云想回家。 +云想(高兴):太感谢你了宋谨哥,店长让我下周周末就可以去工作。 +宋谨:客气啦,妹妹开心我就开心。 +云想:我没有劝成程澈报名参加音乐会,你还帮我,回头我请你吃饭! +宋谨:是你劝成功的。 +云想:什么?程澈说是观鹤找他,他答应的。 +宋谨:观鹤现在天天忙音乐会的事情,时间紧任务重,哪有空找程澈。 +云想(迟疑):是……吗? +宋谨:程澈告诉你的? +云想:嗯嗯,对。 +宋谨:如果我告诉你,他是因为你才表演节目的,你会怎么做? +△宋谨神秘兮兮的看着云想,云想若有所思。 +19-3 场 夜 内 客厅 +人物:云想、程澈 +△云想一路蹦蹦跳跳跑进家门,拍着程澈的房门 +云想:程澈! +△程澈从卧室走出来,半掩着门 +云想:我都知道了! +程澈:什么? +云想:你是因为我才参加音乐会的哦! +程澈:少自恋。 +云想:你就是嘴硬,还不承认。 +程澈:谁告诉你的? +云想:我自己猜的。 +程澈(果断):不可能,以你的智商猜不到……宋谨告诉你的? +云想:跟宋谨哥没关系。 +程澈:宋谨哥?叫的那么好听你要不要去给宋谨当妹妹? +云想:可以吗? +△程澈无语,冲着房间里喊 +程澈:罐头,我们出门溜溜 +△程澈说完作势要开门,云想尖叫一声赶紧逃跑 +第二十集: +20-1 场 日 内 咖啡店 +人物:云想、程澈、蔡怡(咖啡店店长,视觉年龄 25-30 岁左右)、群众数名 +△云想扎着利索高马尾,穿着咖啡店员员工服拿着托盘正在给客人端咖啡。 +△蒋怡端着一杯冰美式咖啡放到前台。 +蒋怡:想想,这是六号桌的哦。 +云想:好的,来啦。 +△云想将咖啡放到托盘上走过去放咖啡。 +云想:您好,这是您的冰美式咖啡。 +△云想抬头看到客人是程澈,程澈靠在椅背看她。 +云想:程澈? +程澈:你在这兼职? +云想:嗯。 +程澈:就你? +云想:我怎么了? +程澈:慢吞吞。 +云想:喝你的吧! +△云想拿着托盘离开,程澈不紧不慢靠在椅背上喝着咖啡看她。 +△云想不停的忙活着,程澈就坐在那里,两人时不时对上视线,云想懒得搭理他继续忙。 +△蒋怡从后厨探出头来。 +蒋怡:想想,六号桌的糖你送一下。 +云想:好。 +△云想拿着糖走过去。 +云想(友好):您好,您要的糖。 +△程澈应了一声,云想撇撇嘴继续去忙。 +△过了一会蒋怡再次喊她。 +蒋怡:想想,六号桌要的吸管你送一下。 +云想:来了。 +△云想再次拿着吸管过去放下。(以下加速) +蒋怡:想想,六号桌要的冰块。 +云想:好的。 +△蒋怡忙活着再次从后厨探头。 +蒋怡:想想,六号桌…… +△云想直接拿着一整盒糖没好气的放到桌上。 +程澈:什么态度啊。 +云想:你有完没完! +程澈:我现在可是顾客,顾客就是上帝,请这位员工注意跟我说话的态度,小心我投诉你! +△云想不情不愿的嘴里嘀咕着骂他。 +云想(嘀咕):什么刁钻的上帝。 +△云想调整心态深深鞠躬微笑面对。 +云想:上帝,对不起,您大人有大量,别生气哦。 +△程澈慢悠悠又加了一块糖端起咖啡杯喝咖啡。 +程澈:心意不诚啊。 +云想(大声):上帝,对不起,请原谅我! +△周围大家都看过来。 +程澈(尴尬):你故意的吧。 +云想:这样吧,程澈,我们休战! +程澈:你猜我同不同意? +云想:不同意是吧? +△云想开口想反驳,程澈站起来用手捂住她的嘴,近距离靠近她的脸,云想不自觉抱紧怀里的 +托盘。 +△两人对视,程澈看着云想明亮的眼睛。 +△咖啡店的门开着,门口挂的风铃随微风轻轻晃动发出清响,仿佛这声风铃响动同时波动了程 +澈的心。 +第二十一集: +21-1 场 日 内 咖啡店 +人物:云想、程澈、蒋怡、男同学(大学生) +△程澈不自觉吞咽唾沫缓缓收回手。 +程澈:行,休战。 +△云想红着脸回到前台,蒋怡早就从后厨忙完出来,正趴在前台看两人的热闹。 +蒋怡:想想,你认识程澈呀? +云想:我跟他不太熟。 +△程澈在这时走到前台付钱,听到云想这句话没否认也没承认。 +△蒋怡左看看云想,右看看程澈,一脸磕到的表情。 +△这时有位大学男同学走到前台找云想。 +男同学:你好同学,你是新来的吗? +云想:你好呀。 +蒋怡:她来兼职的,只有周末过来。 +男同学:多大了?有没有男朋友呀? +云想:我…… +△云想没说话,她下意识看向程澈,程澈此时脸色比庙里夜叉还难看。 +△男同学站在程澈身边,比程澈矮很多,边说话边看着云想,显然很喜欢她。 +男同学:你,你能把 QQ 号给我,我们加个好友吗? +△程澈脸色极其冷漠,一副生人勿近的拽样看他。 +程澈(拽):她年纪小,不谈恋爱,以学业为重。 +云想(震惊):什么? +△男同学跟蒋怡同时震惊看向程澈。 +男同学:你谁啊? +程澈(拽):你管我是谁,她至少喜欢跟她年龄相仿,身高一米八五,学习好,打球厉害的, +就你?叔叔你是哪里人? +男同学:我?!你!!你说什么! +△程澈向前走了一步,居高临下的模样看着男同学,男同学吓得灰溜溜逃走。 +男同学:神经病! +△云想第一次看到程澈这样,她一脸感激。 +程澈(回头):是不是什么人都能认识你? +云想:什么? +程澈:少跟陌生人说话。 +△程澈丢下这句话离开,云想看着他的背影。 +蒋怡:想想,你们在谈恋爱吗?吵架啦? +云想:不不不,高中生不谈恋爱。 +蒋怡:他看上去很在乎你呢。 +△云想再次看向门口,早已没有程澈的身影。 +第二十二集: +22-1 场 夜 外 咖啡店门口 +人物:云想、程澈 +△晚上下班,云想从咖啡店走出来刚锁好门,程澈在身后喊她。 +程澈:喂。 +△云想忙回头找声音来源方向,她看到程澈回去换了衣服,穿着连帽卫衣跟黑色运动裤。 +△云想看着他从阴影处走出来,云想瞪大眼睛张嘴。 +程澈:有这么惊讶吗? +云想:你这是去哪了?打球还是? +程澈:在等你。 +云想:等我? +△云想活动着干一天活酸疼的肩膀。 +程澈:你很缺钱? +云想:也没有,只不过…… +程澈:只不过什么? +云想:只不过是想多赚点零花钱,早点搬出去住。 +程澈:你想搬出去住? +△程澈没有表现的很惊讶,但也还是有一些细微动作,他把手从口袋里拿出来。 +云想:我仔细想了想,我的出现的确对你们造成困扰,还是搬出去比较好。 +△程澈没说话,转身走到前面,云想跟上去,两人并肩。 +22-2 场 夜 外 公路 +人物:云想、程澈 +程澈(突然):很着急? +云想:既然有这个想法,就快点实行吧,总住在你家也不合适。 +程澈 OS:不合适吗。 +△程澈抬头看云想,云想倒退着走路,看上去很轻松并且已经开始思考搬家的事情。 +△程澈伸手拉了一下她的胳膊提醒。 +程澈:好好走路。 +△云想哦了一声转身看路。 +程澈:如果很累就别做了,也不急这一时。 +云想:还好啦,不是很累,怎么了? +△云想笑眯眯贴脸凑过去。 +云想:你是不是舍不得我? +△程澈用手推开云想的脸,云想大大方方的笑着开玩笑,程澈反倒有些失望的看着她。 +程澈:没有。 +云想:真的? +程澈:嗯。 +云想:还以为你会挽留我呢。 +程澈:没必要。 +△程澈很不开心,语气也变得冷漠,云想没有察觉继续往前走,抬头看着路灯下飞来飞去的小 +虫子。 +△安静了几秒,云想双手背在身后,有些小开心的凑过去。 +云想:所以,程澈,你是特意来接我回家的吗? +第二十三集: +23-1 场 夜 外 公路 +人物:云想、程澈 +△程澈愣了一下,云想满脸期待的看着他,他战术性后仰脖子让自己离她不那么近。 +云想:你不要嘴硬了,你刚才都说了,是在等我。 +△云想眨眼前倾身子看程澈,程澈使劲后仰脖子看着她,就这么停顿了几秒,程澈回过神来扭 +头不看她。 +程澈:你知道还问我? +云想:比较想听到肯定的话,比如说。 +△云想学着程澈严肃的样子。 +云想:是的,我来接你回家。 +程澈 ::太傻了。 +云想:不傻,是大聪明。 +程澈:好好,是,接你回来的,行不行? +云想(开心):当然行了! +△两人对视笑了,程澈又说了一边云想傻不傻,云想挥拳要揍他,他往前跑去,云想跟在后面 +看着他。 +云想 OS:自从爸爸去世后,我已经很久没有过这种被别人担心的温暖了,他的出现,就像是 +给我带来了一束光,我们相遇在盛夏,你的出现,明亮耀眼。 +【此处有文案】【文案大意:以叙事的方式来描述她失去亲人要面临第一个夏季,她以为会很 +痛苦黑暗的度过夏季,没想到她遇到了属于她的夏,少年的到来给她带来了一束光,照亮了她 +黑暗的世界。】 +△程澈跑出去几步发现云想没跟上来,他回头,路灯下的柔和灯光把云想整个人衬的很单薄。 +△云想快步跟上去。 +云想:程澈。 +程澈:嗯? +云想:有件事想拜托你。 +程澈:什么事? +云想:我兼职的事情,能不能别告诉程叔叔和阿姨? +△程澈没说话,看了她一眼。 +△云想双手合十态度诚恳。 +云想:拜托了。 +程澈(拽):你求我。 +云想:喂,要不要这么得瑟! +△程澈拿出手机准备给程枭打电话。 +程澈:这会儿我爸应该还没睡。 +△云想摁住程澈打电话的手。 +云想:我求你,行了吧? +程澈:没诚意啊。 +云想:你别太过分哦! +程澈:现在是你求我保密,到底是谁过分? +云想:程澈! +△程澈没回应,真的开始打电话把手机放耳朵上,云想慌了。 +云想:程澈,程澈哥哥,求你啦,帮我保密好不好? +△云想满脸期待,程澈挑眉把手机放下。 +云想:幼稚! +△云想再次朝着程澈背后空气打拳。 +△程澈没回头,挥了挥手里的手机。 +程澈:我可听到了哦。 +云想(小跑跟上):我是说程澈哥哥最好啦,肯定说到做到。 +第二十四集: +24-1 场 日 内 咖啡店 +人物:云想、程澈、宋谨、观鹤、蒋怡 +△今天没有什么客人,云想正在擦桌子,宋谨率先走进来,随后跟着观鹤还有程澈。 +宋谨:想想! +云想:你们怎么来啦? +宋谨:澈哥请客。 +△云想看向程澈,程澈一脸生人勿近的样子冷漠瞥了她一眼,云想立刻移开目光。 +云想 OS:不看就不看,有什么了不起,这里又不是只有他,我看俩! +△云想突然瞪向宋谨跟观鹤,把两人弄的一激灵。 +观鹤:怎么了?我们脸上有东西? +云想:啊,没有没有,请坐。 +△时间过渡,云想端着三杯咖啡走过去放下。 +宋谨:想想,过来坐会儿。 +云想(为难):我在工作呢。 +△蒋怡在前台听到,摆了摆手。 +蒋怡:没关系,你去坐吧,这会儿店里也没什么人。 +云想:谢谢怡姐。 +△云想放下托盘准备坐下,宋谨连忙把自己旁边的凳子挪了挪给她,云想在宋谨身边坐下,她 +的右侧是宋谨,左侧是观鹤,对面是生人勿近的程澈。 +云想:你们去打球啦? +宋谨(叹气):对啊,又是被程澈暴虐的一天。 +云想:没关系,篮球我也会一点,下次我跟你一起虐他。 +程澈:我说,我还在这呢,当我面说? +宋谨:对,当你面说,开心吗? +程澈(假笑):呵呵,开心极了。 +观鹤:对了,明天音乐会,每个班都有同学表演,结束后每人会有三张票让大家投票,前三名 +的班级会有音乐会奖状。 +宋谨:想想,你投给谁? +△云想看了一眼对面程澈,程澈一副生人勿近的模样吓的她缩回去,又看向观鹤,观鹤温柔的 +看着她。 +云想:呃,我…… +宋谨:我先表态啊,我肯定是投澈哥的! +观鹤:你最好小心点,自己班虽然可以投自己班,没有人这么干,明目张胆你会死得很惨。 +宋谨:没关系,我脸皮厚,想想你呢?要不你投别的班吧,咱俩人目标太大。 +云想:观鹤表演吗? +观鹤(摇头):我是主持人,但是也可以投主持人。 +云想:那我投给你吧! +宋谨:就这么愉快的决定了! +程澈:不行。 +宋谨:怎么了?票是妹妹的,妹妹想投谁就投谁嘛,而且我的票投给你哎。 +云想(附和):就是就是。 +程澈:随便。 +观鹤(微笑):谢谢妹妹。 +云想:不客气,那我先去工作啦。 +△云想离开,程澈表情不悦。 +程澈(不悦):她什么时候也成你妹妹了? +宋谨(抢话):什么你妹妹我妹妹的,是大家的妹妹。 +第二十五集: +25-1 场 昏 内 音乐室 +人物:云想、程澈、宋谨、观鹤、群众数名 +△室内音乐会,已经有陆续同学坐在那里等着了,观鹤穿着白色衬衫黑色长裤,很正式好看的 +打扮站在台上跟同学讨论细节。 +△云想坐在下面托腮看观鹤。 +△舞台一侧宋谨跟程澈看向云想。 +宋谨:阿澈,你看想想看观鹤的眼神,甜的嘞。 +△观鹤讨论完细节从台上走下来跟程澈说话。 +观鹤:程澈,你妹不会爱上我了吧? +宋谨:嗯?这句好耳熟,不是我的台词吗。 +程澈:是啊,三票都投给你,估计是了。 +观鹤(语重心长):阿澈,我会对妹妹好的。 +宋谨(紧跟):哥,我也会,我发誓! +程澈:等会结束有本事你俩别走! +△宋谨推着观鹤离开。 +宋谨:快走快走,我感觉到周围涌起杀意。 +△宋谨跟观鹤离开,程澈默默看向云想,洛米走到云想身边递了一个巧克力,云想笑得更开心 +了。 +程澈(自言自语):这么爱吃甜的,小心蛀牙。 +△时间过渡,音乐会正式开始,镜头快速快切模式,第一波上台的是打扮夸张三名女生,拿着 +贝斯摇滚唱 S.H.E《Super Star》。 +△第二波是一名男生,痛哭流涕几度哽咽的唱着《有一种爱叫做放手》, +△第三波一名男声打扮非主流,唱着《你若成风》 +△第四场,观鹤站在台上宣布。 +观鹤:下面有请高三六班程澈演唱,五月天的《纯真》。 +△观鹤下台,周围灯光熄灭,聚光灯照射舞台,灯光变成昏暗氛围感的光线,众人鼓掌欢呼。 +△舞台中央放了一把椅子和立麦,程澈换了一身衣服上台,他穿着白衬衫打黑领带,手里拿着 +吉他,整个人看上去帅气迷人。 +△程澈坐下,周围顿时安静下来,他的目光看向云想,握住话筒开始弹唱。 +程澈:长长的路上,我想我们是朋友…… +△云想猛地抬头,两人周围彻底暗下来,只有中间有光,仿佛这里只有她们二人。 +云想 OS:他唱的竟然是这首歌… +△程澈深情演唱,他一直看着云想,两人对视,他扶着麦腰背挺直,头顶柔和光线落在他身上, +整个人温柔又帅气。 +△云想不自觉向前走了一步,看的出神。云想 OS: +【此处有文案】【文案大意:描写云想被程澈一直保护着,她感到安心而且渐渐沦陷,感慨庆 +幸这个夏天遇到了这个少年。】 +【插入闪回】 +25-2 场 夜 外 巷子 +人物:云想、程澈 +程澈:她是我的人,想欺负她,先看看自己几斤几两! +△程澈把云想拉到自己身后,云想顿时被宽大的后背挡住。 +△程澈为了云想跟他们打架画面闪过。 +△镜头过渡, +25-2A。公交车 +公交车上两人一起带耳机听歌。 +25-3 场 日 内 卧室 +人物:云想、程澈 +△云想趴在程澈怀中,手摸着他的胸肌,两人亲密暧昧姿势对视。 +【闪回结束】 +25-4 场 日 内 音乐室 +人物:云想、程澈、洛米、群众数名 +△云想盯着台上散发魅力的程澈,仿佛整个人的魂被勾走。 +△台上程澈看着云想的表情,得意的嘴角微微上扬笑了笑。 +云想 OS:他刚才是不是冲我笑了?是我的错觉吗? +洛米(激动):天啊,程澈唱歌太好听了。 +云想:嗯嗯好好听啊,他之前还骗我说没有音乐细胞呢。 +第二十六集: +26-1 场 日 内 音乐室 +人物:云想、程澈、群众数名 +△程澈一曲唱完,礼貌的微微弯腰。 +程澈:谢谢大家。 +△程澈下台离开,众人欢呼吹捧。 +26-1A 日 学校走廊 +群众 A:快快,我要给程澈投票。 +群众 B:我也是我也是。 +△云想看向门口,门口放着一张桌子,上面是一个投票箱,这时候已经有人去投票了。 +△云想走神时程澈过来轻轻碰了碰她。 +△程澈跟往常不一样,往常他总爱穿一些宽松休闲的衣服,今天因为表演穿的很正式,五官端 +正帅气中带着一点拽拽的,云想看着他的脸目光慢慢落在他的唇上。 +△程澈捕捉到云想的小表动作,忍不住勾起嘴角。 +程澈 OS:小色鬼。 +程澈:再看你的口水要流下来了。 +云想(擦口水):我没有! +云想 OS:云想,你能不能有点出息! +程澈(笑):你的票,投了吗? +云想:你很在意我投给谁吗? +程澈:六班的规矩,六班的票只能投给自己班,不能便宜外人。 +云想:程澈,你打破我们的规定了。 +程澈:什么规定? +云想(一本正经):四不规则,你离我太近啦! +程澈:我想怎样就怎样,别问,别管。 +云想:那这票我想投给谁就投给谁,观鹤那么好看,肯定要投给他呀。 +△程澈捏她好看可爱的脸蛋扯了扯。 +程澈:云想你完了,你明早吃油条没有白糖了! +云想(挣扎):啊呀!你好狠毒!! +△不远处同学朝程澈挥手。 +程澈:走了 +△程澈离开,云想从口袋拿出三张投票纸站起来走向投票处。 +26-2 场 夜 外 公交车站 +人物:云想、程澈 +△公交车到站,云想下车,程澈刚好骑着自行车从她身边飞过。 +云想:程澈! +△程澈没回应她。 +△她走了两步想到什么,故意假摔坐在地上。 +云想(大喊):啊——好疼! +△几秒钟,程澈骑着车返回来。 +程澈:怎么了? +云想:不小心摔了。 +程澈:这都能摔,平地摔的人只有你了。 +△程澈停车腿撑着地面,没有要下车的意思,他身体前倾伸出胳膊去拉云想,云想抓着他的手 +站起来。 +云想:好疼啊。 +程澈:别装,你看上去像演的。 +云想:是真的 +程澈:还装,我走了? +云想赶忙反手拉住程澈的手臂 +云想:别别别,我突然就好了 +程澈下车,推着车在前面走着 +云想:(小声嘀咕)知道我装还回来 +程澈:我闲的 +云想:程澈,我又没得罪你,你刚才干嘛不理我。 +程澈:不想理就不理,还要和你打声招呼? +云想:我知道…我不是有问你吗,是不是很在意我投给谁?是你不回答我的。(云想双手背在 +身后,开始推锅)还拿我的白糖威胁我。 +程澈停下脚步。 +云想也跟着停下 +云想:怎样? +程澈再次哽住。 +云想:说话! +程澈无语,她还挺凶。 +程澈:对,我在意 +云想顿了一下,怔怔地看着程澈,路灯下两个人的身影被拉长。 +程澈动了动唇,说完这句话,他自己也感觉有些不对劲。 +他皱眉,偏过视线,吞吞吐吐地想再补一句 +云想(打断):嗯,所以我投给你了。 +第二十七集: +27-1 场 夜 外 公交车站 +人物:云想、程车 +△程澈回头看她。 +云想:我真的投给你了,不过只投了两票。 +程澈:另一票给观鹤了? +△云想从口袋拿出票,上面写着程澈的名字,她展示给程澈看。 +云想:这一票我想自己留着。 +△程澈默不作声握紧车把,嘴角上扬浅浅笑着。 +云想:程澈。 +程澈:嗯? +云想:谢谢你唱了我最喜欢的歌。 +程澈(嘴硬):哦,不是我选的,是观鹤。 +△程澈推着车,云想跟在旁边,镜头拉远,云想的声音响起。 +云想:观鹤知道你总拿他当借口吗? +程澈:知道。 +云想:幼稚! +27-2 场 日 外 咖啡店 +人物:云想、蒋怡 +△云想穿着大白熊衣服,蒋怡抱着白熊头。 +蒋怡:辛苦你啦,今天有点热,不用太卖力,工资双倍给你! +云想(笑):谢谢怡姐!那我开始啦。 +27-3 场 日 外 篮球场旁边 +人物:云想、程澈、宋谨、观鹤、路人数名 +△云想戴着白熊头,然后拿着宣传单在篮球场旁边 发着 +△里面是少年们正在热血挥洒汗水打篮球。 +△云想走到路边,听到篮球场里面宋谨的声音。 +宋谨:程澈,你下死手!! +观鹤:歇会儿吧,你已经被他虐了一个上午了。 +△云想看过去,程澈正靠在球网上 +△程澈拿着水瓶仰头喝水,汗水顺着脖颈流淌,云想看着格外诱人忍不住迈着小碎步走进去。 +云想:你好呀。 +程澈:你,好? +程澈 OS:怎么这么耳熟,云想? +△程澈目光落在云想手里的咖啡店宣传单,瞬间明白。 +云想(假装):你好帅呀,我被你完全迷到了,能加你 QQ 吗? +第二十八集: +28-1 场 日 外 篮球场 +人物:云想、程澈、 +△程澈俯身靠近‘白熊’云想。 +程澈(挑逗):有多帅? +△云想双手捧着脸,认真回答。 +云想:超级超级帅,不要到你的 QQ 号,我吃不下饭,睡不好觉。 +△云想趁披着马甲明目张胆,她伸手要去摸程澈腹肌,结果白熊的手太短根本摸不到。 +云想:你忍心看一只熊茶饭不思吗? +程澈(认真思考):嗯……不忍心。 +云想(搓搓手):如果实在不方便,看看腹肌也行啦,然后让熊摸摸就好。 +△程澈低头偷笑。 +程澈 OS:小色鬼。 +程澈:行啊可以看,但是我有条件。 +云想:嗯嗯,你说。 +△云想扶着头套快速点头。 +程澈:把头套摘了,看的会更仔细。 +△云想作为一只熊瞬间呆楞住,程澈笑意加深。 +云想:我,我就看一眼,就一眼。 +△云想戳了戳他的手臂肌肉线条,又白又健壮。 +△云想乖乖点头。 +程澈(挑眉):行。 +△程澈靠近白熊云想,云想眼巴巴看着,程澈微微掀起一角。 +云想 OS:我发誓,看一眼就跑! +△程澈靠的越来越近,云想别扭的后退一步。 +程澈:云想,你是不是真以为我认不出你。 +△不远处宋谨跟观鹤猛地抬头。 +宋谨/观鹤:什么?是云想?! +△白熊云想猛然愣住,站在那里一动不动像个真的玩偶,还有点呆。 +云想(慌张):你,你说什么呢……我听不懂。 +△云想话刚说完,程澈直接将云想的头套摘下来,头套下的云想出了不少汗,发丝黏在脸上, +脸颊通红,对上程澈视线的那一刻,她感到更热了。 +程澈:还看腹肌吗? +△云想咽口唾沫,两人对视,程澈痞痞带着玩味微笑,云想不知所措。 +第二十九集: +29-1 场 日 外 篮球场 +人物:云想、程澈、宋谨、观鹤、蒋怡 VO +云想(尬笑):程澈哥哥,都是误会,我还有事,先走了。 +△云想转身开溜,程澈伸手一把将她揪回来。 +△云想缩脖子一脸无奈被拽回来,她看向宋谨和观鹤投来求救的目光。 +△宋谨观鹤极为默契的同时抬头看向外面,假装没看到。 +宋谨:今儿天气真不错啊。 +观鹤:嗯,没错。 +△云想只能一脸讨好笑着面对程澈,程澈挑挑眉。 +程澈:不看了? +△云想没说话,快速点头。 +程澈:还敢乱撩人吗? +云想(摇头):我错了,再也不敢乱撩了。 +△程澈松开手,云想用笨拙的熊掌勾起程澈的手臂。 +云想:可是,因为是你我才撩的。 +△程澈愣住,低头看着毛茸茸熊掌抚摸手臂,酥酥麻麻还有点痒,夏日午后的风吹过来,吹动 +云想凌乱的头发,程澈看的心里更痒。 +△突然外面传来蒋怡的声音。 +蒋怡:想想!人呢。 +云想:来啦。 +△云想下意识往回跑,跑到一半想起头没拿,返回去冲程澈甜甜的笑了笑,二话不说抱着白熊 +头离开,程澈还站在原地看着她的背影出神。 +宋谨:有个妹妹确实挺好哈。 +△宋谨走过来搭上程澈肩膀,观鹤皱眉严肃。 +观鹤:可是阿澈,你对想想的态度好像不太对劲。 +△程澈看向观鹤,观鹤一脸认真,他自己也开始怀疑。 +观鹤(补充):真的很不对劲。 +程澈:哪方面? +观鹤:各方面都有吧,而且你有没有发现,你从最开始抵触这个私生妹妹,到现在开始接受她 +的靠近。 +宋谨(思考):好像也是,你知道那白熊是她,你还故意陪她演戏逗她玩,坏了!程澈!你的 +狗命要被取走了。 +△程澈看着云想离开的方向若有所思。 +程澈:当哥哥的照顾妹妹也没什么不对,哄小孩本来就是哥哥做的。 +宋谨(挪揄):哦~~ +程澈:你这什么表情! +△观鹤拖着宋谨离开。 +观鹤:快走吧,你嘴太碎了。 +△程澈拿起地上的篮球,突然晃神。 +闪回 +△云想被摘下头套抬头对上程澈视线的那一刻,白白的肌肤透着红,发丝沾在脸上,像受惊小 +鹿一样。 +闪出 +△过了一会程澈回过神来,抱紧篮球 +第三十集: +30-1 场 日 内 教室 +人物:云想、程澈、洛米 +天气:雨 +△上课期间,云想一直盯着窗外,程澈观察到她走神。 +程澈 OS:雨天有什么好看的,上课都能走神。 +△云想看着窗外大雨托腮发呆,默默叹口气。 +△时间过渡,下课铃声打响,洛米收拾书包。 +洛米:太好啦,因为台风咱们不用上晚自习,哎想想,我爸来接我,一起送你吧。 +云想(摇头):不用了,我还有事。 +△程澈刚打算开口,云想拿着伞匆匆离开。 +洛米:你们不一起? +△程澈摇摇头。 +程澈:这么急,去哪…… +30-2 场 夜 内 客厅 +人物:云想、程澈、罐头 +△云想冒雨回家,全身已经湿透,手里提着树莓蛋糕。 +△她小心翼翼把蛋糕放到茶几上,摆好。 +△云想一脸欣喜的看着蛋糕想起往事。 +【插入闪回】 +30-3 场 日 内 客厅 +人物:小云想、云爸 +天气:雨 +△云想趴在窗边看外面大雨。 +云想(开心):下雨啦,爸爸应该快回来了。 +△开门声,云爸穿着雨衣进屋,云想快速跑过去。 +云想(开心):爸爸! +云爸提起手里的蛋糕 +云爸:看看这是什么? +△镜切,画面温馨,云爸云想一起吃着树莓蛋糕 +云想 VO(撒娇):我最喜欢下雨天。 +云爸:为什么? +云想:因为只有下雨天爸爸才不会工作,而且每次回来都会给我带树莓蛋糕呀! +【闪回结束】 +30-4 场 夜 内 客厅 +人物:云想、罐头 +△云想一脸满意,急匆匆回卧室换衣服。 +△云想前脚离开,程澈从楼房间出来,去厨房拿水,罐头紧跟后面。 +△程澈也没在意罐头。 +△罐头趴到桌子上,吃起树莓蛋糕 +第三十一集: +31-1 场 日 内 客厅 +人物:云想、程澈、罐头(狗) +△云想换了衣服从房间出来,发现桌上的树莓蛋糕几乎快吃完了,云想瞬间眼眶湿润。 +云想(大喊):程澈!! +△程澈从厨房跑出来 +程澈:怎么了 +△程澈看了看呆立在原地的云想,又看向被打翻在地的蛋糕,他赶忙拽着罐头撤退,拍它脑袋。 +云想:程澈,那是我买的蛋糕。 +△程澈拍了几下狗头,罐头夹着尾巴认错。 +云想:为什么不看好你的狗? +程澈:罐头!你又偷吃! +云想(怒吼):程澈,它吃了我的蛋糕……为什么让它到处乱跑。 +程澈(皱眉):你有必要这么大声跟我说话吗?腿长在它身上,它去哪是它的自由。 +云想(发抖):但它吃的是我的蛋糕。 +程澈(无所谓):一块蛋糕而已,罐头吃了是它的错,回头我再给你买。 +云想:那不一样。你知道我跑了多少地方,才买到的吗!? +程澈(烦躁):那你说,你想怎么样?把罐头拖出去打一顿?这又不能解决问题。 +△云想委屈,弯腰捡起地上满是奶油的蛋糕盒子。 +△程澈拿抽纸开始擦地上奶油,一边擦一边责怪。 +程澈:既然这么重要,就应该带回房间,放在客厅干什么。 +△云想紧紧攥着盒子一角,又委屈又难过。 +云想:所以我的蛋糕被罐头吃了,是我的错吗? +程澈(平静):我们都有错,行吗? +△程澈擦干净抬头看到云想已经满脸泪痕。 +△云想没说话,程澈突然有些慌了 +云想(哽咽):程澈,你根本不懂这块蛋糕对我的意义。 +△云想哭的很厉害,她跑回房间砰的一下重重关上门。 +△顿时周围安静,程澈低头看着罐头,罐头趴在地上认错。 +第三十二集: +32-1 场 日 外 学校大厅 +人物:云想、程澈、送伞男同学 +天气:雨 +△外面下大雨,云想忘记带伞只能在一楼大厅等雨停。 +△送伞男同学拿着一把黑伞走过来。 +送伞男同学:同学,你要不要雨伞? +△送伞男同学只有一把伞,外面雨下得很大。 +云想:你的伞给我,那你怎么办? +△送伞男同学挠了挠头发有些不好意思。 +送伞男同学:没事,我们男生要照顾女孩子的。 +云想:这雨……应该很快就停了,不过还是谢谢,你不用给我的。 +△送伞男同学显然很高兴,他撑着伞离开,不忘回头道谢。 +送伞男同学:谢谢。 +云想(疑惑):伞不是他的吗,谢我干什么。 +△云想往外探头看了看,雨没有停的意思,依旧乌云密布。 +云想(叹气):唉。 +△程澈戴着连帽衫从楼道走出来,手里拿着黄伞。 +△云想看到他走过来,想起昨晚的事情,主动避开他,往旁边移了一下想跟他拉开距离,结果 +刚转身还没走几步,程澈伸长胳膊拉着云想的书包拽回来。 +程澈:跑什么? +云想:没,没跑。 +△程澈把雨伞递给云想。 +程澈:拿着,校门口直接打车回家。 +云想:那你怎么办? +程澈:不用你管。 +云想:谁想管你。 +△云想还想说话,程澈已经跑进雨幕中,程澈的背影在雨幕中渐渐隐没。 +32-2 场 夜 内 程澈家客厅 +人物:云想、程澈 +△黄伞立在门口的墙边,伞尖处的地面积了一小滩水。 +△云想抱腿坐在沙发上看着窗外,电闪雷鸣。 +云想:怎么还没回来… +△话音刚落,云想听见门口钥匙开门的声音。 +△云想赶紧跑回房间。 +△程澈进来,已经全身湿透,他看了眼脚边的雨伞,知道云想已经安全回家了。 +32-3 场 夜 内 云想房间 +人物:云想、程澈 +△云想听着外面客厅的动静,想要出去,但又在门口止住了。 +△门的另一边,程澈站着,想要敲门的手也止住了。 +△云想看着手里准备好的毛巾,思绪万千。 +【此处有文案】【文案大意:关于开不了口】 +【插入闪回】 +32-4 场 日 外 学校大厅 +人物:程澈、送伞男同学 +△程澈把一把黑色的伞给送伞男同学。 +程澈:同学,你帮我把伞送给门口等雨的那个人,别说是我给的。 +送伞男同学:啊?我跟她不是很熟,她如果不要怎么办? +程澈(皱眉):不要就送你了。 +【闪回结束】 +32-5 场 夜 内 云想卧室 +人物:云想、程澈 +△两人一门之隔,也只有一门之隔,最终都选择转身离去。 +第三十四集: +34-1 场 夜 内 卧室 +人物:云想、程澈 +△云想展开日记本趴在书桌前无精打采的写着什么 +△镜头拉近,日记本上写满了程澈的名字 +云想:讨厌鬼…… +△云想正说着,突然电闪雷鸣吓得云想一哆嗦,紧接着屋内停电,陷入黑暗,云想发出惊叫。 +△窗户一直随风发出巨大声响,紧接着玻璃破碎的声音响起。 +△程澈快速推开门。 +程澈:云想? +△程澈打开手电筒照亮。 +云想:我在,程澈,窗户裂了。 +△周围很黑,只有程澈的手电散发微弱光亮。 +程澈:今晚不能睡这里了。 +云想:那我睡客厅吧。 +程澈:嗯。 +34-2 场 夜 内 客厅 +人物:云想、程澈 +△云想在沙发上安稳躺好,客厅四处点着蜡烛。 +△程澈蹲在茶几前点燃最后一根蜡烛。 +程澈:这样就不黑了? +云想:嗯,好 +程澈:有什么事叫我 +△程澈起身准备离开 +云想:程澈。 +△程澈停住脚步,云想坐起来看程澈, +程澈:什么事? +云想:昨晚是我有些激动了,对… +程澈(打断):对不起…那块蛋糕应该对你很重要吧,云想……不是你的错。 +云想:程澈,谢谢你,程家愿意给我一个落脚地,我已经很满足了… +程澈(情绪复杂):嗯,快睡吧 +云想:好,晚安 +△程澈离开,云想安稳躺下盖好被子。 +△云想缩在沙发小小的,云想抬眼,发现程澈的背影被烛光倒映在墙上。 +程澈坐在云想身后的台阶上 +云想:程澈? +程澈没回应 +云想:程澈?你听到了吗? +程澈:听到了 +云想:我不害怕,你不用陪我的 +程澈:别自恋,我只是还睡不着 +△云想抓着被角偷偷开心。 +云想(小声嘀咕):又嘴硬… +△外面电闪雷鸣,程澈的声音很温柔,云想睡觉,程澈坐在云想身后台阶上,没有离开的意思。 +34-3 场 日 内 程澈卧室 +人物:云想、程澈 +△第二天云想迷糊睡醒,她看清周围后猛地坐起来,头发乱蓬蓬。 +云想:我怎么在程澈房间。 +第三十五集: +35-1 场 日 内 程澈卧室 +人物:云想、程澈 +△第二天云想迷糊睡醒,她看清周围后猛地坐起来,头发乱蓬蓬。 +云想:我怎么在程澈房间。 +△云想打开门,程澈正靠在门口打哈欠,头 +程澈:醒了? +△程澈自然的进去拉开衣柜找衣服。 +云想(惊):程澈我……怎么在你房间啊? +程澈(张嘴就来):你梦游。 +云想:不可能,我从小到大没梦游过。 +程澈:真的是你梦游,半夜自己就爬到我床上,还对我说…… +云想:什么? +程澈(笑意加深):说我好帅,想看看腹肌… +云想(愣住):程澈,你别胡说八道! +△云想逃跑,程澈一脸得逞笑着。 +【闪回插入】 +35-1 场 夜 内 客厅 +人物:云想、程澈 +△云想四仰八叉的睡在沙发上,半个身子都要垂到地上了,嘴里还说着梦话,程澈站在一旁。 +云想:好帅啊…看看腹肌… +程澈:小色鬼 +△突然云想皱眉翻身,动作幅度过大险些掉下去,程澈反应迅速扶着云想。 +程澈 OS:照她这么睡,非得睡到地板上 +【闪回结束】 +35-3 场 日 内 客厅 +人物:云想、程澈 +△云想换了衣服从卧室走出来,程澈下楼。 +程澈:玻璃没修好之前你就睡我房间吧。 +云想:那你睡哪? +程澈:我睡客厅。 +△云想还在犹豫,程澈突然笑了一下。 +程澈:不然我们睡一起也行。 +云想:你还是睡客厅吧。 +程澈(笑):行,早餐吃什么我去买? +云想:我会煮面,我煮西红柿鸡蛋面可以吗? +程澈:你还会煮面呢,当然可以。 +云想(自豪):我爸教我的,爸爸最喜欢吃的就是西红柿鸡蛋面,我的手艺就是跟他学的。 +△程澈突然面色凝重。 +程澈 OS:我怎么不知道我爸会煮面。 +△时间过渡,两人坐在餐桌吃西红柿鸡蛋面。 +程澈(突然):程枭对你好吗? +云想:嗯嗯,对我很好。 +云想 OS:爸爸去世后,一直是程叔叔在照顾我。 +程澈:他这么晚才把你带回家,你不怪他? +云想:程叔叔能带我回家我已经很开心了,我怎么会怪他呢。 +△程澈看她心满意足的样子,他没再说话,低头吃面。 +程澈 OS:对于私生女的身份她竟然毫不在意。 +云想:怎么了,你是不是有话对我说? +程澈:你妈妈,是个怎样的人? +云想(疑惑):我妈妈?她跟胡楠阿姨一样是医生。 +△云想一脸骄傲,笑得更甜了,程澈看着心里不是滋味。 +程澈:云想,你理解她做的一切吗? +云想(摇头):以前不理解,后来慢慢理解了。 +云想 OS:妈妈是为人民服务,是我心中的骄傲。 +程澈:可是云想,她是第三者…… +第三十六集: +36-1 场 日 内 客厅 +人物:云想、程澈、程枭 VO +△程澈话没说完,云想吃着面疑惑看他。 +云想:程澈,你说什么?什么第三者? +程澈:你不知道你妈妈做了什么吗? +△云想放下筷子,一脸严肃,语气坚定。 +云想(认真):我妈妈这一辈子清清白白,把一生贡献给了国家,前线需要支援的时候她二话 +不说去支援,最后连生命都付出了,这就是我知道的妈妈做的事情! +△程澈愣住,不知道怎么开口,云想低下头继续吃饭。 +程澈 OS:所以,她妈妈……如果不是出了意外,我跟妈可能永远不知道这个私生女的存在吧。 +△云想吃完最后一口面,拿着碗去厨房。 +云想:我吃好了。 +△云想快速刷完碗回到自己房间,砰的一下关上门,程澈从没见过慢吞吞的她做事这么快。 +程澈:这么快? +△这时程枭打来电话。 +程澈:怎么了? +程枭 VO:臭小子,大清早谁又惹你了,语气这么冲,家里怎么样,想想在家吗? +程澈:你闺女好着呢。 +程枭 VO:好好照顾妹妹啊,我带队支援不用担心,一切平安。 +程澈:嗯,知道了。 +程枭:有事记得给我打电话。 +程澈:知道,挂了。 +△云想背着书包走出来。 +程澈:云想,刚才…… +云想(打断):上学要迟到了。 +36-2 场 日 内 学校走廊 +人物:云想、送伞男同学 +△上学路上,云想碰到送伞男同学。 +云想:早上好呀。 +送伞男同学:早上好。 +云想:你是那天要把自己的伞给我的同学是吗? +送伞男同学:对啊,你还记得我呀。 +云想:那天谢谢你好心要给我伞。 +送伞男同学:没事啦,你要谢的其实不是我,当时是澈哥让我给你送伞的。 +△云想停下脚步惊讶的看着他。 +云想:程澈? +送伞男同学:是呀,不过我也得谢谢你,不然我要淋雨回家了,哎你后来怎么回去的? +△两人边走边聊,走到班级门口 +云想:啊,后来雨停了,那同学回见。 +△云想离开,送伞男同学站在原地想不通。 +送伞男同学:那天不是下了一天一夜的雨吗? +第三十七集: +37-1 场 日 内 教室 +人物:云想、程澈、宋谨、米蓝 +△【文案大意:那个时候的喜欢很简单,表达喜欢的方式也很简单】 +△【混剪画面: +37-1A +△米蓝写情书折成爱心 +37-1B +△将零食放进抽屉 +37-1C +△折星星 +37-1D +△在桌上刻名字 +37-1E +△编红绳 +△程澈回来坐下从书桌拿出书,连同里面的情书、千纸鹤、折纸爱心掉落一串棒棒糖掉出来, +程澈捡起棒棒糖。 +△云想在旁边做题,程澈把棒棒糖给她。 +程澈:云想,今天早上我说你妈妈的事情,我…… +△云想看到程澈手里粉色情书以及棒棒糖,摇头拒绝。 +云想(打断):这可是你追求者给你的,你给我不太合适呀。 +△云想故意装作柔弱的样子说出来,程澈一脸冷漠。 +程澈:我不爱吃甜的,要不要。 +△云想更是来劲了继续摇头。 +云想:可是,别人给哥哥的,哥哥真的要给我吗? +程澈(隐忍):你想说什么。 +云想:瞧瞧,我不过就是多说了几句,哥哥就这般模样,倘若不想给,那便罢了。 +程澈:云想! +云想:哥哥要是这般态度,倒不如直接不理我好了,显得我无理取闹了些。 +△程澈握拳,棒棒糖险些捏碎,云想回归正经,继续低头写字。 +云想:我不要别人买的,好哥哥你别浪费人家的心意。 +程澈:懂了,你想要我买的? +云想:不要过度分析我说的话啊! +程澈(无奈):我这两天怎么不是在哄你就是在哄你的路上,心累。 +云想:那还不是因为你老欺负我! +程澈:所以呢,你打算怎么办 +云想:你下次还欺负我,就罚你去淋雨,不然不会原谅你! +程澈:哦,那还是别原谅吧。 +37-2 场 夜 内 客厅 +人物:云想、程澈、罐头 +△程澈背着书包放学回家,老远看到罐头趴在地上又吃蛋糕。 +程澈:完了! +△程澈赶忙扔下书包跑过去抓着罐头的脖子,罐头还是成功吃到了几口奶油。 +程澈:罐头,你还敢吃她的蛋糕?!上次给的教训不够? +△罐头耷拉脑袋趴在地上,程澈拍了一下它厚实大脑袋。 +△云想从房间走出来。 +云想:怎么了? +△程澈立刻端正态度站起来认错。 +程澈:云想,罐头错了。 +△云想看向程澈身后的蛋糕,一片狼藉。 +程澈:我发誓,绝对没有下次! +云想:程澈,那是我专门买给罐头吃的。 +△程澈愣住,低头看罐头,罐头摇着尾巴凑过去舔蛋糕。 +云想:它,可以吃蛋糕吗? +程澈 OS:严格来讲,不可以。 +程澈:可以,你原谅它了? +云想:是互相原谅。 +程澈(竖起大拇指):我替罐头感谢你,云想同学您的格局真大,不愧是你人美心善,祝你幸 +福,未来可期。 +云想:我都不用搬出去,已经尴尬的脚趾扣出三室一厅了。 +程澈:你还有这种隐藏技能呢。 +△两人逗乐笑着,罐头欢快吃蛋糕。 +程澈:其实罐头对你没有恶意,它喜欢你。 +△云想摇摇头。 +云想:我跟罐头保持友好关系,距离最好也保持一下下,对了程澈,我很快就可以搬出去了, +等我搬出去,罐头可以在家里随心所欲。 +△原本还在嬉笑的程澈听到这句话,顿时冷下脸来。 +程澈:你钱够了吗? +云想:嗯嗯,老师帮我申请了奖学金,我已经拿到了哦,再加上我平时兼职攒的钱,够啦。 +程澈:云想…… +云想(补充):我周末有时间就去看房子。 +程澈:好,(犹豫)不过其实如果你… +△程澈话没说完,云想的电话在卧室响起。 +△云想跑进去接电话,程澈跟罐头一人一狗看着门口。。 +37-3 夜 内 程澈卧室 +人物:程澈 +△程澈有些沮丧,从包里拿出没送出的棒棒糖 +△程澈打开抽屉将棒棒糖丢了进去 +△抽屉特写:一抽屉装满了棒棒糖 +【文案大意:那时候我们有无数种表达喜欢的方式,都不敢直接说出喜欢】 +37-4 夜 内 云想卧室 +人物:云想 +△云想在接电话 +云想:怡姐,我知道了,我会提前到。 +△云想挂断电话,看向桌子上零零碎碎未折玩的千纸鹤 +第三十八集: +38-1 场 夜 内 客厅 +人物:云想、程澈 +△云想敲了敲程澈的房间门 +△程澈打开门 +程澈:有事儿? +云想:嗯,怡姐说明天晚上有人过生日,要我提前去咖啡厅布置生日会。 +程澈:看上去你答应了。 +云想:反正赚钱嘛,没关系。 +程澈:那你明晚几点回来? +云想:生日会的话估计会晚一点,怡姐说大概十二点。 +程澈(皱眉):这么晚。 +云想:你明天还接我吗? +程澈:如果你希望我去接你的话,我可以考虑考虑。 +云想(干脆):那我希望你来接我。 +△程澈没想到云想这次这么坦然,程澈点了点头。 +程澈:嗯 知道了,早点休息。 +云想:程澈哥哥晚安! +程澈:果然糖吃多了嘴就是甜啊。 +云想:哪有!这是心里话。 +△两人打趣结束对话,程澈自觉去沙发睡觉,云想去程澈房间。 +云想(走到门口):玻璃,什么时候修好? +程澈:应该快了,我明天问问。 +云想:好,晚安。 +程澈:晚安。 +38-2 场 夜 内 咖啡店 +人物:云想、蒋怡、纪恒、男人三名 +△深夜咖啡店,纪恒跟三名男人喝酒,吧台放着蛋糕营造氛围。 +男人 A:老纪,你少喝点酒。 +△纪恒西装搭在椅背,穿着白色衬衫领带歪歪扭扭,整个人醉的说不清楚话。 +△云想跟蒋怡在前台聊天,纪恒一眼看到性感女人蒋怡身边站着青涩乖巧的学生妹云想,他朝 +云想招手。 +纪恒:来,小朋友,把蛋糕端过来。 +男人 B(打趣):这小姑娘倒是很漂亮嘛,很嫩呀。 +△云想端着小蛋糕走过去,纪恒色迷迷看着。 +△云想被看的不舒服,她快速放下蛋糕离开。 +△画面拍摄,时间到十二点。 +△云想托腮看着窗外。 +云想 OS:十二点了,程澈这会儿是不是已经来了。 +△蒋怡拿着钱走过来。 +蒋怡:想想,发工资了,还有这是纪总给你的小费。 +第三十九集: +39-1 场 夜 内 咖啡店 +人物:云想、蒋怡 +△蒋怡把一沓钱给云想,云想大概数了一下。 +云想:怡姐,太多了。 +蒋怡:不多,你收下就行,他们这些老总有的是钱,这点小钱不算什么。 +△云想数出自己的工资钱,把剩下的还给蒋怡。 +云想:怡姐,我只拿自己赚的工资,谢谢怡姐,我先下班啦。 +△云想转身离开,蒋怡看着她的背影。 +蒋怡:这小丫头还挺犟。 +39-2 场 夜 外 咖啡店门口 +人物:云想、纪恒 +△云想站在咖啡店门口等程澈,突然一辆黑色立标奔驰停在云想旁边,车窗降下来,纪恒醉醺 +醺探头。 +纪恒(醉酒):小姑娘,等人吗? +云想(冷漠):嗯,我在等我男朋友。 +△纪恒色迷迷的上下打量云想。 +纪恒:这么小的年纪就谈恋爱了?你应该是高中生吧? +云想:遇到喜欢的人我就死缠烂打追到了,我男朋友很快就来。 +△纪恒突然下车走到云想身边,云想警惕后退。 +纪恒:你男朋友几岁了,也是高中生? +云想(警惕):先生,你好像对我的事情很感兴趣,我们不熟。 +纪恒(笑眯眯):哎呀不是对你的事感兴趣啦,是对你这个人感兴趣。 +△云想警惕再次后退一步跟纪恒保持距离。 +云想:我男朋友马上过来了。 +纪恒:这么漂亮的女孩,你男朋友舍得让你出来打工,一看就不是好男人。 +云想:无可奉告。 +纪恒:你打工不就是为了钱嘛,我给你钱,你跟我走怎么样,保证你以后不缺钱花。 +△说完纪恒色迷迷的抓着云想的手,云想挣扎。 +纪恒:我劝你不要装清纯,给你的这个机会,是无数女人期盼的。 +△云想用另一只手直接一巴掌打下去,纪恒愣住。 +云想:有钱就了不起吗?有钱就能随便侮辱女人吗?! +△一巴掌把纪恒惹怒,纪恒连拖带拽强势要把云想拖进车里。 +纪恒:够野啊,不错,听话的爷玩够了,也该换换口味了! +云想(挣扎):你放开我!! +△云想奋力挣扎朝店里喊。 +云想:怡姐!怡姐!!! +39-3 场 夜 内 咖啡店 +人物:蒋怡 +△蒋怡正跟人打着电话往后厨走。 +蒋怡:你真跟你男朋友分手啦?快展开说说。 +39-4 场 夜 外 咖啡店门口 +人物:云想、纪恒 +云想(挣扎):怡姐!你放开我,你会为你做的事付出代价! +纪恒(嚣张):代价?那我倒要看看究竟是什么代价。 +△纪恒抓着云想肩膀,一把将云想的外套扯下来,用手掐着云想的脖子。 +纪恒:小妞,不乖可不行啊,没事儿,爷有的是时间好好训训你这只小野猫。 +第四十集: +40-1 场 夜 外 咖啡店门口 +人物:云想、程澈、纪恒、男人 A +△云想挣扎着,纪恒掐住她的脖子扬手要给她一巴掌。 +云想(痛苦):我……我男朋友马上就来! +纪恒:男朋友?你以为我真信你说的这种鬼话?你要老老实实还能少吃点苦。 +△云想呼吸困难,纪恒还没来得及打下去,程澈依旧是人没到脚先到,一脚给纪恒踹出去。 +△纪恒醉醺醺的倒在地上爬不起来。 +△程澈低骂一声,云想看到是程澈,顿时眼泪掉下来。 +云想:程澈! +△程澈看向云想,云想头发凌乱外套在地上,眼睛红红的掉眼泪,样子很让人心疼。 +△程澈握拳隐忍着将云想外套捡起来给她披上,把云想拉到身后跟纪恒保持距离。 +云想(哭泣):我以为你不来了。 +程澈:说了来接你肯定会来,对不起,我来晚了。 +△程澈自责又心疼的看着云想,轻轻替云想整理凌乱的头发。 +程澈:他碰你哪了? +云想(委屈):他要睡我!拉我手了!还拽我胳膊了。 +△云想后怕的眼泪止不住,说话的声音都有些抖,程澈温柔体贴的用手给云想擦去脸颊泪水。 +程澈:别怕,我在。 +△云想点头,程澈安抚好云想后走向纪恒。 +△纪恒刚脚步踉跄的站起来,看到程澈阴下来的脸,他嘲笑着。 +纪恒(嘲笑):哎哟,小妞的男朋友来了啊。 +程澈(凶狠):你说什么? +△纪恒还没开口说话,程澈朝着他又是一脚。 +△纪恒本身就醉了,直接重新倒在地上。 +△云想在后面弱弱的解释。 +云想(小声):我怕他欺负我,所以我说我有男朋友了。 +纪恒:原来是假的啊,长得帅有个屁用啊,还不如跟了我。 +云想:我喜欢就行!跟你没关系! +△程澈直接过去抓着纪恒挥拳朝纪恒的脸打下去。 +纪恒(惨叫):你知道我是谁吗!! +程澈:和我有关系吗?穿的人模狗样,实际上猪狗不如! +云想(气冲冲):没错!程澈,把他衣服扒了!让他拽我的衣服! +△程澈没想到乖乖的云想会说这么说,他感到有趣的笑了笑。 +程澈:得嘞。 +△程澈开始扒纪恒外套,纪恒挣扎。 +纪恒:你干什么!!我这身是高定西装! +程澈:我管你什么高定,看清了你欺负的人是谁,她是我的人,别人碰都碰不得! +△云想听到这句话征住,程澈没注意把自己心里话说了出来。 +△这时一起庆生的男人 A 从远处过来,怒斥。 +男人 A:兔崽子!你们干什么!! +△程澈转身一把抓住云想的手(特写)。 +△程澈拉着云想跑走。(慢镜头) +第四十一集: +41-1 场 夜 外 公路 +人物:云想、程澈 +△程澈紧紧抓着云想的手往前奔跑,云想看着程澈,程澈今天穿着校服,似乎有急事没来得及 +换,发丝随风轻轻摆动,校服也随着他的大幅度动作晃来晃去,程澈时不时回头看一眼确保人 +没跟上来。 +△云想攥紧他的手,紧跟身侧跑着,两人穿梭在路灯照射的梧桐树下,树影斑驳,少年眉眼透 +着一股意气风发,云想看的失神,心里悸动。 +△最后两人跑到拐角处停下。 +程澈(大喘气):应该没跟上来。 +△云想弯腰大口呼吸,汗珠顺着脸颊滴落,两人对视笑出声,像是打了一场胜仗。 +程澈:你怎么样? +△两人缓过劲来,才发现手还紧紧的牵着 +△程澈赶紧松开,云想微红了脸,有些害羞 +云想(摇头):我…我没事,程澈,谢谢你。 +程澈:谢什么? +云想:谢谢你总是在我遇到危险的时候出现保护我。 +△程澈看着云想,心中泛起一丝涟漪 +程澈:应该的(察觉自己有些不对劲,找补)哥哥照顾妹妹应该的 +△云想错愕,有点失望。 +云想:所以…程澈,你,一直都把我当妹妹吗? +△程澈犹豫了,他也没想到云想会这么直接。 +时间放佛静止了般,整个世界都在等这个答案 +【此处有文案】【文案:大意“我也想知道在他心里我是什么位置,但我没有问,其实我也是 +敢豁出去爱的,只是,第一步必须你来走,这样我才够有底气”用更客观的视角调整,主题为 +“我们都在等一个答案,又害怕等到这个答案”】 +△程澈愣了愣,莞尔一笑 +程澈:我们…回家吧,时间不早了。 +△云想尽力掩盖着失落 +△程澈手插口袋装作轻松的继续走,云想跟在后面走了两步,才发现刚才跑得太快脚扭了。 +程澈(回头):怎么了? +云想:好像是脚扭了。 +程澈:能走吗? +云想(倔强点头):嗯,能。 +△云想扶着墙壁勉强走了两步。 +△程澈返回去背对她弯腰。 +程澈:哥哥背你。 +云想:没关系,我可以。 +程澈:别逞强,很晚了,该回去休息了。 +△云想张了张口,最后还是没说话,老老实实爬到他背上。 +41-1A 夜 外 家楼下 +△程澈背起云想,两人走在路灯下。 +云想 VO:程澈,是妹妹就足够了。 +【此处有文案】【落版文字文案:好想你知道】 +第四十二集: +42-1 场 日 内 客厅 +人物:云想、程澈、胡楠 +△云想从卧室出来,胡楠担心的看着云想。 +胡楠:想想,脚怎么样啦?实在不行我给你请一天假吧。 +云想(摇头):没事阿姨,已经不疼了。 +胡楠:哎哟以后跑步的时候小心点。 +云想(愣住):啊,好。 +△程澈拿着书包从卧室走出来。 +胡楠:小澈,跟想想一起。 +△程澈还是快步走着没等云想。 +胡楠:这臭小子,也不等你一起,一点都不绅士,也不知道随谁。 +云想:没关系阿姨,那我先去上学啦。 +胡楠:去吧,慢点走。 +42-2 场 日 内 学校教室 +人物:云想、程澈 +△云想进教室,程澈提前到了,正收拾书本。 +云想:早呀。 +△云想笑着主动跟他打招呼,程澈冷冷看了一眼,拿着稿子转身离开。 +云想:我又哪里惹到他了吗…… +42-3 场 日 内 学校广播站 +人物:程澈、米蓝(高二班花)、教导主任 +△程澈正在看广播站投稿本子发呆,突然教导主任带着米蓝走进来。 +教导主任:程澈,这时高二一班的班长米蓝,从今天开始她跟你一起广播。 +△米蓝有些害羞的看着程澈,她主动走过去伸出手要跟程澈握手。 +米蓝:学长好,我叫米蓝,以后多多照顾啦。 +△程澈直接无视米蓝的示好,低头继续看稿子。 +程澈:广播站不一直是一个人播嘛? +米蓝:学长,我只是来学习播音的,今后要考播音主持方面。 +程澈:我不是专业的,你来这里跟谁学习? +△程澈抬头看向米蓝,米蓝愣住。 +米蓝 OS:知道他不好相处,没想到这么难相处。 +△教导主任直接拉着程澈到一旁小声说话。 +教导主任:程澈,这是校领导安排的,如果你们后面实在不合适我再想办法。 +程澈(不耐烦):老师,现在有两个选择,一是我自己播,二是我做交接,以后让她播,两个 +人没法播。 +△教导主任为难的挠挠头。 +教导主任:嗯行,你先带她播几天吧。 +△程澈皱眉,转头看向米蓝,米蓝站在那里有些害羞。 +米蓝:学长,我学东西很快,不会给你添麻烦的。 +△程澈没说话,拿着稿子坐下,教导主任给米蓝使眼色,米蓝拿着小板凳坐在旁边,教导主任 +轻轻关上门。 +△米蓝看着程澈戴上耳机,一脸崇拜的样子。 +42-4 场 日 内 学校教室 +人物:云想、程澈 VO、米蓝 VO、洛米、同学 AB +△教室内,云想正在看书,广播准时响起。 +程澈 VO:同学们好,现在是广播站时间,今天广播站来了一位新朋友,接下来让她做一下自 +我介绍。 +△云想抬起头,旁边的同学震惊。 +米蓝 VO:同学们好,我是高二一班的米蓝,以后我会跟程澈学长一起广播。 +△同学们沸腾起来。 +同学 A:竟然来了个女播音员,广播站一个人就够了呀。 +同学 B:米蓝哎,她可是高二一班的班长,还是班花呢。 +同学 A:米蓝?好耳熟的名字,是不是那个喜欢程澈很久的同学? +△云想继续看书,心思却不在书上。 +△洛米回头问云想。 +洛米:想想,你听程澈说过广播站要来人的事儿吗? +△云想摇摇头,看上去无动于衷。 +洛米:她绝对不是奔着广播站来的,她是奔着程澈来的呀! +云想:程澈那么优秀,有女同学喜欢也是正常的啦。 +△洛米手肘搭在桌子上靠近云想。 +洛米:但是这有点靠的太近了!两个人天天一起播音,一旦王八看绿豆看对眼了,那后果不敢 +想呀! +△云想抬头看着小喇叭发呆。 +云想 VO:难道程澈是因为米蓝,才… +第四十三集: +43-1 场 日 内 学校教室 +人物:云想、程澈、米蓝、宋谨 +△程澈跟米蓝一起回来,云想通过教室后门看到。 +米蓝:学长,我刚来广播站,还有很多不懂的地方,要麻烦你多教教我啦。 +△米蓝笑得很温柔,长得也很漂亮。 +△云想抬头看过去。 +米蓝:那学长我先走啦,有不懂得我再问你。 +△米蓝笑着挥手离开,程澈没说话,转身进教室。 +△云想慌忙回到自己座位坐好 +△镜切,程澈在云想身旁坐下 +△云想犹豫了会儿,把老师给的试卷交给程澈。 +云想:沈老师让我给你的。 +程澈(冷漠):嗯。 +△程澈冷漠的接过试卷,云想还想说什么,程澈不理她将试卷随手一放,拿起书。 +云想:程澈,你。 +△云想还没说完,宋谨拿着 AD 钙奶走进来。 +宋谨:想想! +△云想抬头。 +宋谨:我和观鹤打球,他输给我一瓶 AD 钙奶,给给给,吃! +△云想接过 AD 钙奶,笑得又乖又甜。 +云想:谢谢宋谨哥! +△宋谨走过去搭上程澈肩膀。 +宋谨:澈哥,和班花合作感觉怎么样呀? +△云想观察着两人,表情失落。 +云想 OS:校草跟班花,的确很配。 +程澈:什么怎么样? +宋谨:哎哟还装呢,人家可是班花啊,去广播站不就是冲你去的嘛。 +△程澈拉开椅子坐下,云想正在喝着 AD 钙奶看书。 +△宋谨拉旁边的椅子靠过去八卦。 +宋谨:你小子桃花太多了,你喜欢米蓝那样的吗? +程澈(冷漠):不喜欢。 +宋谨:那你喜欢什么样的?我看哪位同学能让我们澈哥心动。 +△程澈没说话,宋谨伸长胳膊拍了拍云想的脑袋,云想呆呆的正在吃糖。 +宋谨:想想这样的呢?喜不喜欢? +△夏日微风吹动教室内的窗帘,云想不经意间对上程澈的视线。 +△云想紧张的咬着糖果,程澈皱眉移开视线。 +程澈(反问):我是畜牲? +宋谨(打趣):不好说哦。 +程澈:滚! +43-2 场 日 内 食堂 +人物:云想、程澈、米蓝、洛米、宋谨 +△云想跟洛米端着打好的饭菜坐下,洛米用胳膊碰了碰云想。 +洛米:哎,你看。 +△云想看过去,不远处米蓝端着打好的饭坐在程澈对面。 +洛米:这个米蓝果然是因为程澈才去的广播站啊,现在俩人都在一起吃饭了。 +△云想咬着筷子看向两人,宋谨端着饭菜走过来坐下。 +洛米:你们不跟程澈一起吃吗? +宋谨:我们才不去当电灯泡呢。 +△宋谨贴心的把自己碗里的鸡腿夹给云想。 +宋谨:来,想想,哥的鸡腿给你吃,吃! +云想:谢谢宋谨哥。 +洛米:就知道想想吃!想想都快被你喂胖了。 +宋谨(敷衍):你也多吃点。 +△洛米白了一眼宋谨。 +宋谨:想想,咖啡店的兼职还顺利吗? +云想:嗯嗯,还不错。 +△这边刚说完,不远处的米蓝把筷子一摔,云想等人同时看过去。 +宋谨:哇塞,这是发生什么事了。 +第四十四集: +44-1 场 日 内 食堂 +人物:云想、程澈、宋谨、洛米、米蓝 +△程澈跟米蓝这边,米蓝不断讨好程澈。 +米蓝:打饭阿姨多给我夹了一个鸡腿,我吃不完这么多,给你吃吧。 +△米蓝主动把鸡腿夹过去,程澈一脸冷漠。 +程澈:你跟食堂阿姨也有关系?我不爱吃 +米蓝(尴尬):你尝尝嘛,很香的。 +△程澈抬头看着米蓝,一脸严肃生人勿近。 +程澈(冷漠):我说了我不吃,拿走。 +△米蓝被吓一跳,只能重新把鸡腿夹回自己碗里。 +△程澈继续沉默吃饭,米蓝找话题。 +米蓝(热情):哎程澈,我们加个 QQ 吧,有事的话也方便联系。 +程澈(不耐烦):我不方便 +米蓝(愣住):程澈,加 QQ 也是为了广播站的工作能够顺利进行。 +程澈:不用了,我会辞掉广播站的工作,以后你自己播。 +米蓝:什,什么?你就这么讨厌我吗? +程澈(干脆):嗯。 +△米蓝握紧筷子,生气的看着程澈,程澈一脸无所谓继续吃饭。 +米蓝:你不就是长得好看点嘛,有什么了不起的! +△米蓝将手中筷子扔到地上。 +△程澈的脸冷下来,眼神冷厉带着不容拒绝的气势。 +程澈:给你三秒,捡起你的筷子,滚。 +△米蓝委屈的站起来没有动作。 +程澈:三、二…… +△程澈开始倒数,米蓝不情愿捡起筷子哭着跑走。 +△另一边,云想正咬着鸡腿看戏。 +云想:发生什么事了? +宋谨(解说):看样是聊崩了。 +△程澈抬头看过来,对上云想视线,云想立即低头扒拉米饭。 +洛米(感叹):哎,程澈这家伙,一天到晚不知道要伤多少女孩的心呐,所以说还是做朋友走 +的长远。 +云想(喃喃自语):朋友…… +宋谨:我们澈哥,就是有魅力! +△宋谨得瑟,云想若有所思的吃着饭。 +44-2 场 夜 内 客厅 +人物:云想、程澈 +△云想放学回家,程澈正在端菜,今天还是他们两个人在家。 +云想:程澈。 +△程澈没回应云想,将碗筷摆放好。 +云想:程澈,你听到了吗? +程澈(回应):怎么了? +△程澈没抬头,继续盛饭。 +△云想走过去。 +云想:我是不是哪里惹到你不开心了? +△程澈摇头,没说话,甚至看都不敢看她。 +云想:那你干嘛忽然这么冷漠,我做错事了吗? +△云想的声音很委屈,程澈忍不住抬头看,云想表情委屈,眼巴巴看着程澈希望得到答案。 +【此处有文案】【文案大意:描述男主的心境大意于“因为太在意,所以得装的不在意,因为 +太想靠近,所以更要保持分寸”】 +第四十五集: +45-1 场 夜 内 客厅 +人物:云想、程澈 +△程澈楞了一下,低下头把米饭碗放下。 +程澈:你没有做错事,是我的问题。 +云想:和我有关系吗? +△程澈给云想放筷子的手顿住。 +程澈(淡淡):没有,吃饭吧。 +△云想坐下吃饭,两人很安静没有说话。 +△云想忍不住主动说话。 +云想:我明天要去咖啡店,怡姐说他们要跟我道歉。 +程澈(冷漠):嗯。 +云想:你能不能陪我去? +△程澈抬头对上云想亮晶晶期待的眼睛,他移开视线一脸拽样。 +程澈:再说,看我有没有空。 +△云想不开心他的反应,她学着米蓝的样子握紧筷子。 +云想:我都问你为什么不开心了,你还是不理我,我又没做什么,你拽什么拽! +△云想骂了一句把筷子往桌上拍,结果动作太大筷子掉在地上。 +△云想往房间跑,程澈叫她。 +程澈:云想,你回来! +△云想跑到门口回头嚣张。 +云想:我是不可能像米蓝那样捡起来的,你自己捡吧! +△云想开门进去,重重关上门。 +△程澈一脸无奈去捡地上的筷子。 +45-2 场 日 内 咖啡店 +人物:云想、蒋怡、代表(40-1 场的男人 A) +△云想跟蒋怡在咖啡店等纪恒来道歉,蒋怡抱歉的拉着云想的手。 +蒋怡(自责):想想,我那天没听到你叫我,我后来看监控了,姐对不起你。 +云想(摇头):没事姐。 +△代表推门进来,腋窝夹着一个皮包,一脸傲慢的样子。 +△蒋怡把云想挡在身后保护。 +蒋怡:纪总没来吗? +代表(嚣张):多大点事儿啊,还用的着麻烦纪总? +△代表看蒋怡身后的云想,笑得很假。 +代表(讽刺):不就是道歉吗,对不起,行了吧? +蒋怡(生气):你这是什么态度?! +代表(假笑):不好意思啊,我就这态度,你接受就接受,不接受拉倒! +△代表从皮包里拿出几张钱靠近云想,蒋怡挡在前面。 +代表:你出来打工不就是为了赚钱嘛,这些钱够吗? +△代表直接把钱扔在蒋怡跟云想身上。 +△云想握紧拳头站出来。 +云想:对,打工就是为了赚钱,但不代表我什么钱都赚,把你这些肮脏的钱拿走,脏了我们的 +地板! +△云想一脚踩在地上的钱,蒋怡不敢相信乖乖女会这么做的表情看她。 +第四十六集: +46-1 场 日 内 咖啡店 +人物:云想、程澈、蒋怡、代表、纪恒 +△代表生气的指云想,云想高傲仰起头。 +代表(生气):行,你等着! +云想:好,我就在这里等着,我看你们到底要怎样! +△代表情绪失控,冲动的上去推了一把云想,多亏蒋怡站在后面及时接住云想,云想才没有摔 +倒。 +蒋怡:你怎么推人啊! +△代表推完人就要走,程澈开门走进来,门口风铃晃动。 +代表:是你? +△程澈站在门口堵住他的去路,眼神冷厉。 +程澈:你再推她一下试试? +代表(嚣张):我推她怎么了,这是你女人? +程澈(冷笑):是又怎么样。 +△云想跟蒋怡同时看向程澈,程澈今天穿了一身运动服,袖子撸上去很像是来干架的。 +△代表从皮包里掏钱。 +代表:不就是想讹钱吗,多少钱,你开个价吧。 +程澈:格局小了,我们报警,你等警察来吧。 +程澈(看向蒋怡):怡姐,监控都还在吗? +△蒋怡伸手比 OK。 +蒋怡:在的在的。 +代表(愣住):我…… +△纪恒推开门进来,代表开始慌张擦汗。 +纪恒:真巧啊,大家都在,怎么样,解决了吗? +△代表低头畏畏缩缩。 +程澈:解决什么?这是你们来道歉的态度? +代表(委婉):纪总,我态度很诚恳的道歉了,人家不原谅还报警了。 +程澈(怒):拿钱侮辱人也叫道歉?!真当小姑娘好欺负,家里没人是不是? +△程澈站到云想跟前挡着,云想握紧的拳头松开,安全感满满。 +△纪恒笑脸讨好,控制场面。 +纪恒:别生气别生气,你是她的? +程澈(高傲):男朋友! +云想(呆住):嗯? +△蒋怡在一旁捂着嘴偷笑,一脸磕到的表情。 +△程澈握住云想的手,把云想拉到身边搂着,宣示主权的样子高傲的看着纪恒。 +纪恒(笑):好好,我知道了,小伙子你别生气,我们今天来是解决问题的,大家不要激化矛 +盾。 +△纪恒诚恳的看着云想,程澈搂的更紧了。 +纪恒:我重新跟小姑娘道歉,咱们私下和解,别报警,你看行不行? +程澈:想和解可以,看你们的诚意。 +纪恒:哎哎,好。 +△纪恒伸手,代表主动把皮包递给纪恒,纪恒要拿钱。 +程澈(制止):你还想再侮辱我们一次吗? +△纪恒表情很难看,他慢慢放下手。 +程澈:钱在你看来是万能的是吗,能帮你摆平一切? +纪恒:不是不是,那你说怎么解决才能原谅我。 +程澈(高傲):带着八件礼品登门道歉。 +△众人震惊。 +第四十七集: +47-1 场 日 内 咖啡店 +人物:云想、程澈、蒋怡、纪恒、代表 +△纪恒拿出手帕擦汗。 +纪恒 OS:看上去这小子很棘手啊。 +程澈:带上八件礼品到家里拜访,这才是正儿八经的道歉,是我们那儿的规矩。 +纪恒(迎合):行行,我们登门拜访。 +△云想握住程澈的手,摇头暗示不用这样。 +程澈:怕什么,你又没做错什么。 +云想:我不想让程叔叔跟阿姨担心,算了吧。 +△云想走到程澈前面看着纪恒。 +△纪恒有眼力见的鞠躬弯腰道歉。 +纪恒:对不起,那天我喝醉了,对不起。 +云想:你的道歉我接受了。 +程澈:什么? +纪恒:你真的接受了? +云想:嗯,你走吧以后不想再看到你。 +△纪恒高兴的点头答应,然后跟代表离开。 +蒋怡(困惑):想想,就这么算了? +云想:嗯,道歉就够了。 +△云想拉着程澈的手晃了晃,真诚的看着云想。 +云想:谢谢你,程澈。 +程澈:好,我尊重你的想法。 +△蒋怡一脸吃瓜群众的开心表情。 +蒋怡:哎呀都男朋友了还这么客气呀。 +云想(慌张害羞):骗他们的。 +蒋怡:不是男朋友? +云想:不是啦,是……哥哥。 +程澈:走吧,回家。 +云想:怡姐我们回去了。 +蒋怡:嗯,路上小心。 +47-2 场 日 外 公路 +人物:云想、程澈 +云想:你不是不来嘛。 +程澈:路过。 +△云想伸手拉住程澈的衣角,程澈偏头看她。 +云想:这两天你为什么忽然对我这么冷淡? +程澈:有吗? +云想:有!和你第一天见到我的态度一样,让人陌生。 +程澈:哦 +云想:程澈,我以为我们至少算朋友了。 +程澈:朋友? +云想:不算吗? +程澈没有说话 +云想:如果你把我当朋友,你就不能这样对我… +程澈(打断):不算,不算朋友。 +云想征住,一时不知道怎么回答,刚要说点什么被打断 +程澈:而且我也不想和你做朋友。所以,请你以后注意下分寸。 +云想眼中闪过一丝悲伤,很快又被藏了起来 +两人对立二站,蝉鸣不再响起,风也不再温柔 +【此处有文案】【落版文字文案:我不想和你“只”做朋友】 +第四十八集: +48-1 场 日 内 程澈卧室 +人物:云想、程澈 +△第二天程澈准备去敲房门,云想已经穿戴整齐背着书包出来。 +程澈:早。 +云想:早。 +程澈:早饭好了。 +云想:你先吃吧,我今天要早点去学校,有事… +△说完便笔直朝门口走去,程澈突然有些不适应,心中有些落寞 +云想:程澈 +程澈回头,有些期待 +程澈:我在 +云想:窗户什么时候来修? +程澈:快了,就这两天 +云想:好 +云想推门出去,剩下程澈一人 +48-2 场 日 内 教室/走廊/ +人物:云想、程澈 +教室里程澈刚在座位坐下,云想拿着试卷起身离开 +走廊里云想和洛米说笑聊天,从程澈身边走过,放佛没看到程澈 +云想坐在台阶上,戴着 MP3 发呆 +程澈坐在广播站,戴着耳机发呆 +[48-3 场 日 内 广播站 +人物:程澈、米蓝 +△程澈发着呆,米蓝不好意思的走起来。 +米蓝:程澈,那天在餐厅,对不起。 +程澈:嗯。 +△程澈冷冷答应,拿起稿子。 +程澈:你播还是我播? +△米蓝眼眶红红的,她抓紧衣角。 +米蓝:你播,我不会再来了。 +△米蓝委屈的擦眼泪跑走,程澈也不回头,直接坐下戴耳机准备广播。 +48-4 场 日 内 学校教室 +人物:云想、程澈 vo、洛米 +△广播开始,这次只有程澈的声音,洛米回头八卦。 +洛米:哎想想,你听,那个米蓝好像不在广播站了。 +云想:哦。 +洛米:看来程澈又是自己一个人播了,我听说上次的情书,就是米蓝找人送的。 +云想:情书? +洛米:对呀,上次那封粉色情书,我亲眼看到米蓝的同桌偷偷塞进他课桌里的。 +云想:只有情书吗? +洛米:嗯嗯对呀。 +云想 OS:难道那天的棒棒糖是他买的。 +洛米:想想,你明天周末有事情吗?要不要出来玩? +云想(摇头):明天我得去咖啡店兼职,对不起哦米米。 +洛米:没事儿没事儿,我们想想可是事业型女强人。 +第四十九集: +49-1 场 日 内 客厅 +人物:云想、程澈、胡楠、程枭 +△云想在门口穿鞋,胡楠走过去。 +胡楠:想想,大清早去哪呀,我看天气预报等会下雨。 +云想:阿姨,我有点事情,晚点回来。 +胡楠:行,记得带伞,对了,修窗户的今天会来,我等会去上班,你不在家的话让小澈替你看 +着点。 +云想:嗯嗯,谢谢阿姨,我先走啦。 +△云想开门匆匆离开。 +云想(喃喃自语):要迟到了。 +△云想离开,胡楠看着玄关的雨伞叹气。 +胡楠:这孩子,跑的真够快,伞都没拿。 +49-2 场 日 内 云想卧室 +人物:程澈、维修师傅、云想 VO +△时间过渡到下午,程澈帮助云想挪书桌方便师傅来修窗户 +程澈:师傅,您看下好不好修 +师傅:好嘞 +△程澈刚挪动书桌,日记本掉在地上,因为中间夹着笔,掉落的时候笔掉出来,日记本也被打 +开。 +△程澈弯腰捡起来,看到云想的日记本。 +程澈:云维安?名字怎么这么耳熟。 +△程澈突然想起什么,他继续翻看日记本。 +程澈:10 月 28 号…… +△插入云想画外音。 +云想 VO:夏末,老天夺走了我的爸爸,我失去了在这个世界上最后的亲人,程叔叔告诉我, +爸爸他是个英雄,我知道爸爸是个英雄,是人们心目中的英雄,可是我心中的英雄,永远不在 +了…… +【穿插第一集,云想第一次来程家的单人氛围镜头】 +△程澈激动的手止不住颤抖,他继续快速往后翻。 +云想 VO:爸爸,今天下雨了,还记得你总是会在下雨的时候买一块树莓蛋糕回家看我,今天 +也下雨啦,爸爸,你会回家吗?我给自己买了一块树莓蛋糕,因为只有这样,我才会觉得你还 +在我身边…… +【穿插云想在桌前写日记的镜头,以及往集对应画面镜头】 +△程澈继续往后翻,日记本有几张空白的,上面画着简笔画罐头还有程澈,旁边配字。 +云想 VO:明天晚上程澈还会来咖啡店接我吗。 +云想 VO:罐头很可爱,可我还是怕狗。 +△程澈站在原地看了很久,手不停的抖,他回想起跟云想争吵时,云想说的话。 +云想 VO:程澈,你根本不懂这块蛋糕对我的意义! +△程澈眼眶泛红,迅速合上日记本跑出去。 +49-3 场 日 内 客厅 +人物:程澈、程枭 +△程澈拿着日记本跑出卧室,迎面撞见刚进门的程枭。 +程枭:跑这么快干什么。 +程澈:爸,原来云想是云叔叔的女儿…… +第五十集: +50-1 场 日 内 客厅 +人物:程澈、程枭 +△程枭看到程澈手里拿着云想的日记本。 +程枭(生气):程澈,你怎么这么没礼貌,不可以乱动别人的东西,更不能看别人的日记本, +这是人家的隐私! +△程澈现在根本听不进去程枭的话,他的耳朵一阵轰鸣,只能看到程枭的嘴巴一张一合,根本 +听不清说的什么。 +程澈:爸,是吗? +程枭:你不知道? +程澈:他们都传,云想是你在外面的私生女。 +△程枭爽朗笑着,拍了拍程澈的肩膀,程澈还站在原地愣着根本没动作。 +程枭:我哪有那个本事,我要是真有想想这么懂事儿的女儿就好了。 +程澈(追问):所以云想住在我们家是因为云想的爸爸去世了? +程枭:对啊,我没跟你说过吗?哎呀,忙忘了! +程澈(崩溃):这么重要的事情你忘了!!你知不知道…… +△程澈回想起对云想说的话,他几乎崩溃。 +程枭:知道什么? +△程澈把日记本塞给程枭往门口跑。 +程枭:去哪啊,外面下雨了。 +程澈:我出去一趟。 +△程澈拿起伞冲出去。 +50-2 场 日 内 咖啡店 +人物:云想、蒋怡 +天气:雨 +△云想急匆匆推开门进来,此时店里还没有人。 +云想:对不起怡姐,我迟到了。 +蒋怡:没关系,你有事的话晚点来也行,你最近是不是很忙呀? +云想:嗯,我最近在忙着找房子。 +蒋怡:找房子?你要搬出去住? +云想:嗯怡姐,你知道哪里的房子出租吗? +蒋怡(思考):我还真知道一家,我朋友出国了,房子一直空着,我打电话帮你问问。 +云想:嗯嗯,谢谢怡姐。 +△蒋怡拿着手机打电话进入后厨。 +△咖啡店因为下雨没有客人,云想走到窗前桌前坐下,托腮看着外面大雨。 +云想 OS:下雨了… +50-3 场 日 外 公路 +人物:程澈 +天气:雨 +△程澈撑着伞跑进雨幕,脚步溅起一滩水花,大雨将他淋湿他都没有在意,满脑子全都是云想 +红着眼睛看他,以及开心的笑脸。 +△(画面闪回) +程澈 OS:我前几天还说她妈妈是第三者,我怎么这么混蛋。 +程澈 OS:她一定很讨厌我。 +程澈 OS:她竟然不是我妹妹,云想,云想…… +△程澈跑的越来越急促,此时此刻他迫切的想要见到云想,雨点淋在他身上,将他的衣服头发 +淋湿。 +△窗外程澈冒着雨朝这边跑来,云想看到熟悉的身影,两人对视 +第五十一集: +51-1 场 日 内/外 咖啡店门口 +人物:云想、程澈、蒋怡 +天气:雨 +云想:是程澈吗? +△云想推开门出去,看清来人 +云想(震惊):程澈?这么大的雨你怎么来了 +△程澈站在雨中,心里的愧疚像是洪水猛兽,看到云想的那一刻决堤,他握紧雨伞一动不动 +△雨越来越大,云想冒雨跑过去拉程澈想让他进屋。 +△直到云想淋雨,程澈才反应过来,他把伞倾斜过去给她打伞,自己肩膀一半露在外面。 +△程澈低头看着云想,眼神都变得柔和起来。 +△云想注意到他的肩膀露在外面,她握住程澈打伞的手(慢动作唯美感),朝程澈的方向挪了 +挪。 +△程澈低头看着云想握住自己的手,整个人呆呆愣住,眼眶已经泛红。 +△两人对视,几乎同时开口。 +云想/程澈:我有话对你说 +程澈:你先说。 +云想:我终于要找到房子了。 +△程澈的话到嘴边欲言又止,他眼睛直勾勾看着云想,从云想的脸上能看到喜悦,可他怎么也 +高兴不起来。 +云想:你要说什么? +程澈(反应过来):哦,没,没什么。 +△蒋怡在这时推开门朝外喊。 +蒋怡:你们两个笨蛋在干什么?雨中浪漫吗,快进屋,感冒可不是闹着玩的。 +51-2 场 日 内 咖啡店 +人物:云想、程澈、蒋怡 +△咖啡店的投影里播放着《恶作剧之吻》男女主淋雨片段:袁湘琴“过一阵子,我们就会搬出 +去…” +△蒋怡给程澈毛巾擦拭。 +蒋怡:你不是手里拿着伞吗,怎么全身湿透了。 +程澈(找借口):年轻人出汗多。 +蒋怡:嘴硬。 +△云想换完衣服走出来,咬着发绳拢了拢头发扎高,侧面刘海还有些湿。 +蒋怡:想想,告诉你一个好消息! +云想:是不是房子的事情呀? +蒋怡:没错!我朋友说房子闲着也是闲着,你要住就去住吧,但是要自己交水电费哦,还有不 +能损坏屋里设施,不要带陌生人进去。 +云想(高兴):太好啦,谢谢怡姐,但是房租该付的得付。 +蒋怡:好好,那就按照外面正常房价给你打个六折。 +云想:嗯嗯好,谢谢怡姐! +△程澈目光流露出失落 +△蒋怡看看程澈,再看云想,一脸磕到表情。 +蒋怡(笑):你俩也快回家吧,今天估计没什么客人了,过会我也打算关门啦。 +云想:嗯嗯,那我们先走啦,对了怡姐,你这里还有伞吗? +蒋怡(摇头):我就带了一把伞。 +云想:好吧,那我们先走啦。 +△云想跟程澈打着同一把伞离开。 +△离开后,蒋怡看向角落的两把伞。 +第五十二集: +52-1 场 日 外 公路 +人物:云想、程澈 +天气:雨 +空镜 +△两人共撑一把伞,雨已经小了很多。 +云想:程澈,我想去个地方。 +程澈:买树莓蛋糕? +云想:你怎么知道的? +程澈:我猜的。 +云想:你知道我为什么喜欢吃树莓蛋糕吗? +△程澈握紧雨伞,朝她的方向倾斜,摇摇头没有说话。 +云想:因为我爸爸,以前每次下雨他都会回家,还会给我带一块树莓蛋糕,所以我很喜欢。 +△云想转身倒着走看程澈。 +云想:程澈,谢谢你。 +△程澈的雨伞完全倾斜在云想身上,雨浠沥沥下着,街道两旁的路灯散发黄色暖光,程澈背挺 +得很直,一脸宠溺看着云想。 +程澈:谢我? +云想:谢谢你来接我呀,我今天早上出门走的急,明明阿姨提醒我带伞的,我还是忘了。 +程澈:嗯,真笨。 +云想:才不是! +△两人走在路灯下的雨幕中,程澈突然停下脚步。 +程澈(突然):云想,对不起。 +云想:什么? +程澈:对不起,之前说你妈妈的话,对不起。一直以来,是我错了,是我的错。 +△程澈跟云想诚恳道歉,云想看着他炙热的目光,听的云里雾绕,但还是笑着大方拍拍他肩膀 +安慰,这让程澈更自责。 +云想:我已经原谅你啦,毕竟你已经受过惩罚了。程家能收留我,我已经很感激了,不过我应 +该过几天就可以搬走啦。 +△程澈看着云想,没有说话。 +云想:怎么了? +程澈(有些着急):女孩子自己一个人在外面住,不是很安全,你在程家住的不开心吗? +云想:开心呀,但是一直麻烦你们总归过意不去,而且罐头本来在家里是自由的,因为我,它 +客厅都不能待。 +程澈:罐头已经习惯了,这不重要,也不是你一定要搬出去的理由。 +△程澈说的有些着急,就差抓着云想的肩膀说。 +△云想疑惑的看着他。 +△程澈低下头,语气放轻。 +程澈:我的意思是,你不搬出去也行。 +云想:嗯……你在挽留我?(歪头看他)是不是舍不得我呀? +程澈(嘴硬):罐头喜欢你,你要是走了,它会抑郁的。 +云想(笑):是吗? +△云想歪头看程澈的表情,程澈故意仰头不给她看。 +程澈:嗯。 +△程澈躲着,云想追着(小美好) +第五十三集: +53-1 场 日 内 客厅 +人物:云想、程澈、胡楠 +△云想跟程澈在客厅吃早餐。 +程澈:没想到昨天蛋糕店关门那么早。 +云想:没关系的。 +程澈:下次我再给你买树莓蛋糕。 +云想:好! +△程澈吃饭快,他喝完最后一口牛奶,云想看到快速把面包往嘴里塞。 +△胡楠端着一杯牛奶放下给云想。 +胡楠:慢点吃想想。 +△程澈第一次吃完早饭没有走,他托腮看着云想塞得嘴巴满满当当像个小仓鼠。 +程澈:你慢慢吃,我等你。 +云想(愣住):嗯? +△程澈把牛奶推到她前面,云想嚼着面包口齿不清的说话。 +云想:你,在等我? +程澈:嗯,慢慢吃,我自行车坏了,从今天开始和你一起坐车。 +△云想刚喝了一口牛奶,听到程澈温柔的话牛奶喷出来不小心溅到程澈脸上。 +△胡楠站在旁边看呆。 +△云想慌忙放下牛奶抽了几张纸站起来前倾身体给程澈擦脸上的牛奶,动作有些粗鲁快速。 +△程澈握住云想的手腕制止,胡楠假装没看到转身离开。 +胡楠(小声自言自语):哎呀,我锅还在灶上呢。 +△胡楠离开。 +云想(忍笑):对,对不起。 +程澈:云想,你故意的吧。 +△云想看到程澈的模样没忍住笑出来,程澈不但没生气,反而双手捏着云想的脸蛋扯了扯。 +程澈:行了,慢慢吃。 +△云想坐回去,开始慢慢吃饭,程澈自己用纸巾擦脸。 +△胡楠偷偷探头看着两人。 +胡楠(笑):小澈这两天很不对劲啊,是不是要恋爱了。 +53-2 场 日 内 公交车 +人物:云想、程澈 +△两人上车,车内坐满了人,程澈跟云想只能站着。 +△云想抓着把手站在前面,程澈抓着另一个把手把云想半护在怀里。 +△期间上车下车挤来挤去,云想都被程澈保护的很好。 +△云想抬头看程澈,程澈看着窗外,她小心翼翼挪动跟程澈拉开一点距离。 +△公交车继续,最后一站司机来了个紧急刹车,云想没站稳手松开把手,整个人朝程澈怀里撞 +进去,程澈抱住云想护着。 +程澈:啧。 +△云想保持一个动作僵住,她双手此时环抱着程澈,左脚还不小心踩在了他的鞋上。 +△云想缓缓抬头,跟程澈对视上,她尴尬的苦笑松手,脸已经红透了。 +云想:不好意思啊。 +程澈(调侃):没关系,回头给我刷鞋就行了。 +云想:好好,妹妹给哥哥刷鞋就是了。 +△云想生闷气转头背对程澈,程澈看着她样子笑得更开心了。 +第五十四集: +54-1 场 日 内 学校教室 +△人物:云想、程澈、宋谨、观鹤、洛米 +△教室内,观鹤抱着球靠在门边朝里喊程澈跟宋谨。 +观鹤:走了。 +宋谨:来啦,澈哥,走!今天咱俩吊打观鹤。 +程澈:走吧。 +△程澈从口袋拿出两根棒棒糖放到云想桌上,云想正研究课题入迷,程澈顺手揉了揉她脑袋。 +程澈:回头哥教你。 +△程澈心情极好的跟宋谨勾肩搭背离开。 +洛米在一旁一脸震惊 +洛米:程澈刚才是十分宠溺温柔的摸了你脑袋吗?他吃错药了? +云想(强装镇定):嗯,是吧,我也觉得他这几天不太对劲 +△云想低头看到桌上的棒棒糖,偷笑。 +54-2 场 日 内 学校走廊 +人物:程澈、宋谨、观鹤 +△程澈跟宋谨走出来,观鹤把球投给程澈,程澈接住球。 +宋谨:什么情况。 +程澈:什么? +观鹤:情况不对。 +宋谨:澈哥,你惨了,你要坠入爱河了。 +观鹤:她可是你妹妹啊。 +程澈:妹妹又怎么了。 +宋谨:啧啧,不行,这爱河不能让你入,你不能这么狗,还是让我来吧。 +△说着宋谨回头要去找云想,程澈抓着他领子拎回来。 +程澈:你敢去一个试试。 +宋谨:观鹤,救命,他真的坠入爱河了。 +54-3 场 日 内 食堂 +人物:云想、程澈 +△云想一个人在食堂吃饭,突然大鸡腿夹过来放到云想碗里,云想没抬头想都不想脱口而出。 +云想:谢谢宋谨哥! +程澈:你满脑子只有你宋谨哥? +△云想抬头,看到来人是程澈。 +云想(开玩笑):好巧同桌,你也在吃饭啊。 +△程澈又捡了盘里的肉夹给云想,云想左右看看连忙捂着自己的盘子。 +程澈:不巧,我特地来找你的。 +云想:你要干什么?菜里不会下毒了吧?你要毒害我?我什么都不知道。 +△程澈用筷子敲云想脑袋。 +程澈:少跟宋谨一块玩。 +△云想呈防备状态挡住,很滑稽可爱。 +云想:在学校你可从来没有跟我一起吃过饭,不是要保持距离吗? +△云想神秘的凑过去,压低声音。 +云想(低声):程澈,你别忘了你说的四不许。 +程澈:那四不许是规定你的,不是规定我的。 +云想(假笑):呵呵,你这是典型的只许州官放火不许百姓点灯! +△程澈一只手推着云想的额头让她坐好。 +程澈:我愿意,吃你的饭。 +第五十五集: +55-1 场 夜 内 教室 +人物:云想、程澈、宋谨、观鹤 +△下课铃声打响,晚自习放学。 +宋谨:澈哥,再打会球去? +△程澈刚想开口,忽然看向云想。 +程澈:你去吗? +云想(摇头):我?我又不会打球,你们去吧,而且怡姐让我待会过去把合同签了。 +观鹤(疑惑):什么合同? +云想:怡姐帮我在学校附近找了个房子。 +观鹤:你要搬出去住? +云想:嗯嗯,我先走啦。 +△云想背着书包离开了教室。 +△宋谨有些犹豫开口。 +宋谨:一个女孩子出去住是不是不太安全啊,你没挽留吗? +△程澈装作不在乎,轻描淡写回应。 +程澈(嘴硬):挽留了,她自己的想法随她吧。 +宋谨:你爸爸同意?虽然关系的确有点特殊,但总归不太放心啊。 +程澈:我爸不知道,关系挺普通的。 +观鹤:关系普通? +程澈:嗯,她有自己的爸爸,跟我们家没什么关系。 +宋谨:自己的爸爸?哪个爸爸? +程澈:云想的爸爸。 +宋谨:啊? +程澈:云想根本不是我爸的私生女,是他们传谣。 +宋谨(震惊):我去兄弟,好大的瓜啊,这么说你跟云想没有血缘关系? +程澈:肯定没有啊。 +宋谨:太震惊了,等等,难怪你之前不让我们当你妹夫,原来…… +△宋谨一脸看懂的表情,观鹤补充。 +观鹤:所以你… +程澈:打你们的球去吧。 +△程澈起身离开教室。 +55-2 场 夜 内 咖啡店 +人物:云想、程澈、蒋怡 +△云想来到咖啡店,蒋怡正把合同拿出来给云想。 +蒋怡:想想,租房合同你看看有没有问题,没问题的话签字吧。 +△云想刚伸出手来,程澈快步跑进来接过合同。 +云想(震惊):程澈?你怎么来了? +程澈:不能签,这合同有问题。 +第五十六集: +56-1 场 夜 内 咖啡店 +人物:云想、程澈、蒋怡 +△云想跟蒋怡震惊的对视。 +蒋怡:什么问题? +△程澈跑了一路,气喘吁吁拉椅子在云想身边坐下。 +程澈:反正合同不能签,这房子不能住。 +蒋怡:你什么意思?这一共就几条规矩,事先跟想想沟通好的,能有什么问题? +云想(点头):对呀,合同没有问题呀。 +△程澈看向蒋怡,投来拜托恳求的表情,蒋怡瞬间明白,叉腰点头。 +蒋怡(思考):这合同…… +△程澈不断给蒋怡使眼色,蒋怡只好把合同收回来。 +蒋怡:想想,这合同确实有点简单了,如果你住着出了什么事儿,那谁也担待不起呀,这样吧 +想想,你等我回头找个律师,完完整整拟一份合同。 +△程澈终于松口气,拿起桌上水杯喝了口水,一路跑过来累的大汗淋漓。 +△蒋怡拍拍云想肩膀。 +蒋怡:想想,先回去吧,合同的事有结果我通知你。 +△云想看透了程澈的小表情,她有点生气不满的背上书包。 +云想:嗯,那怡姐我们先走了。 +蒋怡:嗯嗯,走吧走吧。 +56-2 场 夜 外 咖啡店门口 +人物:云想、程澈 +△两人走出咖啡店。 +云想:没签成都怪你,这下你满意了? +程澈(笑):嗯,满意了。 +云想:幼稚! +△云想回头去踩程澈的鞋,程澈侧身躲开。 +云想:我肯定要搬走的,你能阻止我一次,还能阻止我第二次吗? +程澈:是我意思还不够明显吗?,云想,留…… +△程澈话没说话,云想捂住他的嘴,手指放在唇边做静音动作,程澈看着她的软唇有点出神。 +△下一秒,程澈握住云想的手腕拉开。 +程澈:云想,留下来。 +△两人对视两秒,云想抽回手继续往前走。 +云想:看心情吧。 +△程澈跟上去。 +程澈:云想,你最近有点嚣张了啊! +云想:哥哥误会人家啦,人家哪敢嚣张呀。 +△云想故意装柔弱,程澈不紧不慢应对。 +程澈:没关系,哥哥这个嘴啊,也没个把门的,说不定什么时候我就告诉你亲爱的程叔叔说你 +在外面打工,还找房子搬出去住。 +△云想措不及防回头踩了程澈一脚,程澈没反应过来结结实实挨了一下。 +云想:程澈,你玩不起! +程澈:云想!你别太过分啊! +△云想背着手倒着走路,高高的仰着头。 +△一阵风吹过,同时吹动了少年的心,程澈看着得意的云想,两人在不知不觉间拉近距离,无 +数个夜晚,都是他们一起回家的。 +△程澈双手插兜眼底满是宠溺,云想欢快的走在路灯下,彼此看着微笑。 +【此处有文案】【文案大意:少年的心事无法言说,他不喜欢她离开自己,舍不得她离开。】 +第五十七集: +57-1 场 日 内 客厅 +人物:云想、程澈 +△第二天清晨,云想从卧室背着书包慌忙跑出来,程澈靠在门框等着她。 +云想:要迟到了! +△云想拉着程澈拽走,两人跑出去。 +57-2 场 日 外 巷口 +人物:云想、程澈 +△云想拉着程澈的手,两人狂奔。(画面洋溢青春) +△程澈笑的一脸开心。 +云想:来不及了!再晚赶不上公交车就得下一趟,上学会迟到。 +程澈:要是赶不上我骑车载你去。 +云想:你车不是坏了吗? +程澈:哦…是哦,坏了。 +57-3 场 日 内 公交车 +人物:云想、程澈 +△两人终于赶上公交车,坐在公交车最后一排,云想气喘吁吁。 +云想:我发誓闹钟一响我就起! +△程澈拿出自己的 MP3,递给云想一个耳机。 +程澈:下回你要不起我让罐头亲自服务喊你起床。 +云想:谢谢啊,我拒绝。 +△云想自然的接过程澈的耳机,两人戴着同一个耳机听歌。 +△音乐播放周杰伦《简单爱》。 +云想:这首歌好熟悉,叫什么名字来着? +程澈:叫…你先听我想想 +△说着程澈将另一个耳机也给云想戴上了 +云想:不是,你直接看一下歌名不就行了 +程澈:是哦 +△程澈拿起 mp3 假模假式的看着。 +程澈:这首歌叫… +△云想看着程澈,耳机声音很大,只能看清嘴形好像是四个字 +△云想摘下耳机 +云想:没听清,叫什么? +程澈:我只说一遍,没听清就算了,回头分享给你。 +云想(撇嘴):哦。 +57-4 场 日 内 学校教室 +人物:云想、程澈 +△云想在教室写着作业。 +△小喇叭响起程澈的声音。 +程澈 VO:广播站点歌时间,来自高中部匿名同学的投稿,来自周杰伦的《简单爱》。 +△音乐响起前奏,云想抬头。 +云想:对,就是这首歌,小气鬼,还是让我知道了吧。 +△云想一愣回想起公交车上看到的嘴形 +云想:我怎么记得他说的是四个字,这歌还有另外一个名字吗? +△云想摇摇头接着埋头轻声哼着这首歌做题。 +【闪回画面:程澈轻声说出“我喜欢你”】 +第五十八集: +58-1 场 晚 外 公交车 +人物:云想、程澈、蒋怡 VO +△公交车准时停下,两人上车,晚上的公交车上面没有多少人。 +△两人刚坐下,云想手机响起,是蒋怡打来的。 +蒋怡 VO:想想,合同我重新弄好了,房子也收拾的差不多啦,你要过来再看看合同吗? +△云想看向程澈,手机的音量比较大,程澈完全听到了。 +云想:怡姐,我……搬。 +△程澈低头拿出 MP3 插耳机。 +△程澈依旧自然干脆的递给云想耳机,云想接过来。 +云想:程澈,我……。 +程澈:我尊重你的选择。 +云想:那…你可以陪我一起告诉程叔叔跟阿姨吗? +△程澈抬头看云想,云想安静的看着他,两人很平静氛围又有些奇怪。 +程澈:好。 +△程澈冷冷的答应,扭头看向车窗外。 +58-2 场 夜 内 客厅 +人物:云想、程澈、程枭、胡楠 +△程枭跟胡楠同时震惊的看向彼此。 +程枭:想想,你要搬出去住? +胡楠:想想,为什么想搬出去住呀,是不是我和你叔叔太忙了,对你的关心不够,所以你想搬 +出去。 +云想:不是的阿姨,你们对我很好,是我自己的原因。 +△胡楠转头看程澈,程澈无奈耸肩。 +胡楠:是不是程澈欺负你了?这臭小子!小澈,你快跟想想道歉。 +程澈:我? +△程澈指自己,一脸无辜。 +云想:阿姨,不是的,跟程澈没关系,他对我很好,是我自己不想住在这了。 +程枭(皱眉):想想,你是不是怕麻烦我们? +△云想低下头没说话,胡楠拉住云想的手。 +程枭:你爸爸跟我是好兄弟,更像是一家人,现在他不在了,照顾你是我的责任,你怎么会觉 +得是麻烦我们呢。 +△胡楠拉着云想在沙发坐下,眼中满是温柔。 +胡楠(温柔):想想,留下吧,你不麻烦我们的,阿姨我早就把你当自己的女儿了,你在家里 +住了这几个月,如果走了,我们这心里还空落落的呢。 +△胡楠诚恳轻声温柔的跟云想说话,云想红着眼眶看胡楠,胡楠温柔笑着点点头。 +云想(小声):可是我……我和帮我找房子的怡姐说好了。 +程澈(补充):合同不是还没签吗。 +△云想抬头看程澈,程澈笑着。 +程澈:你看他们不会同意你搬的。 +△云想松开胡楠的手站起来,毅然决然。 +云想:叔叔阿姨,对不起,我还是得搬,我这周六搬,谢谢你们对我的照顾,我很感激,我也 +会照顾好自己的,对不起。 +△不等他们说话,云想快速逃离回房间。 +58-3 场 夜 内 云想卧室 +人物:云想 +△云想回到房间,从抽屉拿出小时候和父亲的照片。 +云想(自言自语):爸爸,我终究要成长的,我不能一辈子住在程家,对不对? +我害怕…我害怕我在这里待得越久,越舍不得走了 +【此处有文案】【文案大意:“越孤独的人,越怕喧闹;越渴望,越怕深陷,太过留恋的代价 +是依赖,但我没有承担的底气,因为往后,我能依靠的只有自己”】 +△云想偷偷哭泣。 +第五十九集: +59-1 场 夜 内 程澈卧室 +人物:程澈、宋谨 VO、观鹤 VO +△程澈在二楼阳台倚在栏杆上,卧室内没有开灯,手机屏幕亮起微弱光亮。 +△手机开着免提,响起宋谨跟观鹤的声音。 +宋谨 VO:想想真的要搬出去吗? +观鹤 VO:你没挽留她? +宋谨 VO:唉,她应该是怕麻烦澈哥他们家。 +观鹤 VO:嗯,阿澈,你怎么想的。 +△程澈双手撑在栏杆上看着外面夜色。 +程澈:我不知道,你们有没有好主意? +宋谨 VO:想想心最软了,要不你装病吧!试试看? +观鹤 VO:哈哈这招有点损,不是你澈哥的风格,他应该不会这么做。 +程澈:什么馊主意,先挂了。 +△电话关断,程澈皱眉叹气。 +59-2 场 日 内 客厅 +人物:云想、程澈、胡楠 +△第二天早餐,云想正在吃早餐,程澈脸色极差顶着黑眼圈坐下。 +△云想观察程澈。 +云想:你怎么脸色这么差? +△程澈头发有点乱,黑眼圈也重,显得很疲倦虚弱。 +△胡楠走过来。 +胡楠(担心):小澈,你是不是生病了。 +△说完程澈立刻咳了咳。 +程澈:嗯……我没事。 +△胡楠摸了摸程澈的额头。 +胡楠:也不烫呀。 +程澈:可能昨晚着凉了,我没事妈,咳咳咳。 +△程澈继续咳嗽,云想担心的看着程澈。 +△胡楠拿了体温计过来 +胡楠:夹个体温。 +△程澈嗯了一声,不忘偷瞄了下云想。 +胡楠(面色郑重):想想。我昨晚和你叔叔回到房间针对你搬出去的事儿又聊了一下,我们两 +个意见统一,都不同意你搬出去。 +云想:阿姨… +胡楠:想想。不是阿姨戳你伤疤。你爸妈都是为国捐躯,你是英雄的女儿,既是天下的女儿! +我们任何人都有义务照顾你!倘若我们连你都不照顾,我们配得上为人吗?” +△云想认真听胡楠说话,眼眸渐渐湿润。 +胡楠:你什么都不用说。只需要把我的话消化掉,最后,去留由你! +六十集: +60-1 场 日 外 学校阶梯 +人物:云想、程澈、群众数名 +△云想戴着耳机,坐在阶梯上发呆。她闭上眼睛,微微仰起脸,任由风拂过脸颊。 +△胡楠的话不断在耳畔回响,让她有些犹豫 +△身边忽然有人坐了下来,云想没睁眼都知道是谁。 +云想:程澈嘛。 +云想:说是不许靠近你,某人却一次一次靠近我。 +△她睁开双眸,一双眼有些朦胧地望向他。 +云想:你说,这算怎么一回事儿? +△程澈双手环胸,脸上没什么情绪,只是眼神往她身上瞟了一眼。 +云想:还是不舒服吗? +程澈(有气无力):嗯 +云想:发烧了吗? +程澈:不知道。 +△云想抿了抿唇,见他脸色依旧不好,不禁微微皱眉。 +△就在程澈要垂头时,她忽然靠近,抬手将手背贴在了程澈的额头上。程澈心尖一颤,他瞬间 +抬眸,对视上云想那双亮晶晶的漂亮眸子。 +△她摸了摸自己的额头,又贴了一下程澈的额头 +云想:不发烧呀,为什么会看起来这么虚弱啊? +程澈:头晕。 +云想:要不要去医务室看看? +程澈:不要。 +云想:生病不看医生,会好吗? +程澈:你如果不搬了,可能会。 +云想(咂舌,反应过来):程澈,你该不会是在装病吧。 +程澈:我是那样装病的人吗? +△程澈越是反驳,越是露出马脚。 +△云想撇撇嘴,而后看向天空笑了,程澈知道,自己被怀疑了,他立刻侧过身子,抬手捏住云 +想的脸 +程澈:喂。云想,信任呢! +△云想的脸被他掐住,嘴巴嘟起来,说起话来有些含糊不清 +云想:喂狗了。 +△云想抬手,掰开了他的手指,推开他的手。 +云想:说话就说话,怎么动手动脚的? +程澈(认真):怎么就这么倔。非要搬出去不可? +△云想低着头,双手绕来绕去 +云想:我和怡姐说了晚上去签合同。 +△程澈一阵沉默。 +第六十一集: +61-1 场 昏 内 咖啡店 +人物:云想、蒋怡、程澈 VO +天气:雨 +△云想正在看合同,蒋怡拿着笔走过来给云想。 +蒋怡:想想,签了字合同可就生效了。 +△云想拿笔,下意识看向外面,似乎看到了程澈当时接自己的画面。【幻觉,第三视角】 +【穿插男主在学校教室看到窗外下雨】 +△云想看到程澈站在门口,‘云想’开心的跑出去,两人对话。 +“云想:程澈,你是来接我回家的吗?” +“程澈:嗯,来接你回家。” +【第二段】 +“云想:你怎么在这?” +“程澈:笨蛋,等你回家呀” +△幻觉结束。云想托腮悠悠叹气。 +云想 OS:他今天还会来接我回家吗。 +△云想想起程澈白天的问话。 +程澈 VO:非搬不可吗? +云想 OS:是啊,是不是非搬出去不可呢。 +△蒋怡拉开椅子坐在云想身边。 +蒋怡:又下雨了,这雨季没完没了。 +△云想看着窗台发呆,希望能看到程澈的身影。 +蒋怡:想想,你带伞了吗?马上转秋,秋雨最凉了,如果淋了雨容易发烧的,走的时候拿把伞 +哈。 +61-2 场 昏 内 家 +人物:程澈、罐头 +程澈坐在沙发上发呆,罐头过来蹭了蹭程澈 +程澈捧着罐头脑袋 +程澈:以后就没有人给你喂蛋糕吃咯 +程澈说完愣了下,然后慌忙冲出了屋子 +程澈 OS:也许,如果今夜买到了树莓蛋糕,我就能留下云想 +如果买不到…不,一定能买到 +61-3 场 昏 外 路 +人物:程澈 +天气:雨 +△画面一转,程澈正站在蛋糕店门口,蛋糕店关着门,程澈给程雅(程姑姑)打电话。 +△打了两次,程雅没接电话。 +程澈:来不及了。 +△雨越下越大,程澈冲进雨幕往另一家蛋糕店跑。 +61-4 场 昏 内 蛋糕店一 +人物:程澈、店员 A、云想 +△程澈浑身湿漉漉的跑进一家蛋糕店,下雨缘故蛋糕店没有人,店员还感到惊讶。 +△画面给到墙上时间,下午六点。 +程澈(迫切):你好,请问有树莓蛋糕吗? +店员 A:抱歉,没有哦,这个点我们都打算关门啦。 +△程澈看了一眼时间,有些焦急。 +程澈:那可以定做吗? +店员 A(摇头):很抱歉,这个口味基本上都不做了。 +【幻想视角】 +云想湿漉漉的,在前台留着电话 +云想:这是我的联系方式,要是哪天又开始做了麻烦您联系我 +云想说完转身离开 +【镜头拉开带出程澈,回到现实】 +程澈 OS:云想那天应该找了很久吧 +程澈:谢谢。 +△程澈说了声谢谢匆忙离开,推门的瞬间风夹杂雨灌进来,程澈没有犹豫跑进雨中。 +61-6 场 夜 内 蛋糕店二 +人物:程澈、店员 B、云想 +△程澈跑到第二家蛋糕店,满怀希望的推开门,同样的情况蛋糕店没有客人,店员正坐在椅子 +上看手机。 +程澈:你好,请问你家有树莓蛋糕吗? +△店员站起来摇摇头。 +店员 B:树莓蛋糕?没有。 +【同插入云想跑进店询问】 +61-7 场 夜 内 蛋糕店三 +人物:程澈、店员 C、云想 +△时间过渡,程澈在第三家店询问,店员摇头 +【同插入云想跑出店】 +61-8 场 夜 外 路 +人物:程澈、云想 +【云想推门出,衔接程澈跑出来】 +△程澈从蛋糕店跑出来 +程澈/云想 先后踩过一滩水,溅起水花 +程澈/云想(分屏)在大雨中继续跑,雨水湿透他们的衣服。 +【此处有文案】【文案大意:少年是什么样的,他们总是害羞,喜欢把心事藏在不起眼的事物 +里,一块蛋糕、一根棒棒糖、一首歌、一阵风; +他们也偶尔冲动,把这些不起眼的事当作天大的事,为了那些他们自以为了不起的意义,喊破 +了嗓子撞破了头,拼命奔跑,他们甚至都不知道要冲向哪里,不过这些都不重要,冲!就对了, +这就是少年!】 +第六十二场 +62-1 场 夜 外 路 +人物:程澈、群众数名 +△程澈低头沮丧,任由雨水将他淋湿,他也不紧不慢的继续走着。 +62-2 场 夜 外 咖啡店门口 +人物:云想 +云想撑起伞,看着远方,眼中透着失落 +云想 OS:今天他应该不会来接我了 +【此处有文案】【文案大意:少年的沮丧,挽留,买不到的蛋糕,以及他的自责。他没有办法 +为她买一块树莓蛋糕,就像她要搬出去,他一样也没有一点办法。】 +62-3 场 夜 外 路 +人物:程澈、群众数名 +周围的路人有的打伞匆匆走过,不忘回头看他一眼,有的路人没有带伞,快速从他身边跑过去, +只有他走在雨里,没有躲雨。 +△这时程澈的手机响起,程澈接听,脸上终于带了一种释然的笑意。 +62-4 场 夜 外 姑姑蛋糕店门口 +人物:程澈、程雅(程姑姑) +△程澈坐在程雅的蛋糕店门口台阶上,也不躲雨,就这样淋着雨,他看着过往车辆,没有任何 +波动。 +△过了一会程雅打着伞走过来,看到程澈像个委屈的小孩一样坐在台阶,被雨整个淋湿。 +程姑姑:大半夜的你怎么一个人在这淋雨,找我到底是什么事? +△程雅对上程澈目光,程澈有些疲惫,眼眶都是红的。 +62-5 场 夜 内 姑姑蛋糕店 +人物:程澈、程雅 +△程雅丢了个毛巾给程澈 +程雅:真有你的,全身都湿透了,这么晚找我到底干什么? +程澈:我想要一块树莓蛋糕。 +△程雅停下手里的动作看向程澈,程澈全身湿透还滴着水。 +程雅:大晚上在这淋雨等我就是为了一块蛋糕?你疯了? +程澈(自言自语):嗯! +程雅:你不是不喜欢吃甜的?等等,下雨……树莓蛋糕。 +程雅:我想起来了,前些日子有个小姑娘,跟你……(上下打量)现在一样,浑身湿透了,似 +乎跑了好几家店,也是为了一块树莓蛋糕。 +程雅:姑姑今天没有做树莓蛋糕,卖的不是很好,换别的行吗? +程澈:不行,必须是树莓蛋糕。 +程雅:这大晚上的,你是要我现在给你做? +程澈:嗯。 +程雅:你小子,该不会是… +程澈:嗯,我喜欢她。 +第六十三集: +63-1 场 夜 内 客厅 +人物:云想、程澈 +△很晚程澈才到家,虽然打着伞但身上还是湿了一半,他将蛋糕用衣服裹在怀里。 +△云想趴在客厅的桌子上等程澈等的睡着。 +程澈看看云想,露出安心的笑容 +△云想似乎听到了动静,惺忪的睁开眼睛,刚好对上程澈的眼神 +云想:程澈,你回来了。 +程澈(温柔):嗯,我回来了。 +云想(坐起):你怎么这么晚才回,衣服还湿了 +△程澈将怀里的蛋糕拿出来,微笑的看着云想 +程澈:找了好久 +△云想一愣,瞬间红了眼眶 +△程澈缓缓走向云想,到桌前,单膝跪下,将蛋糕小心翼翼的放到桌子上 +【插入闪回 1】 +63-2 场 夜 内 云想家客厅 +人物:小云想、云爸 +天气:雨 +△爸爸把蛋糕放到桌子上 +△小云想开心的抱着爸爸 +小云想(开心):最喜欢爸爸啦,爸爸以后每天都要给我买蛋糕 +云爸(慈祥):等爸爸老了可能就不能给你买蛋糕了 +小云想:爸爸永远不会老,爸爸要活一百岁,一千岁,一亿岁 +爸爸(笑了笑):好好好,就算爸爸买不了,爸爸也一定会找个人代替爸爸给你买树莓蛋糕吃, +呵护你宠着你。 +【插入闪回 2】 +63-3 场 夜 内 巷子 +人物:云想、程澈、黄毛青年 +△程澈及时出现保护云想,将云想拉到身后,如同“英雄一般”独自走向持棍子的黄毛青年。 +【插入闪回 3】 +63-4 场 日 内 公交车 +人物:云想、程澈 +△上学路上,公交车内有人上车下车挤来挤去,云想都被程澈保护的很好。 +△最后一站司机来了个紧急刹车,云想没站稳手松开把手,整个人朝程澈怀里撞进去,程澈抱 +住云想护着。 +【闪回结束】 【以上男女主闪回情节可替换】 +63-5 场 夜 内 客厅 +人物:云想、程澈 +云想(哭):程澈,你是不是傻了,淋雨买蛋糕,这都凌晨一点了! +程澈:这就感动了?你也太好糊弄了,你这个样子搬出去住,很容易被人骗的… +△程澈话还没说完,云想过去紧紧抱住程澈。 +△程澈抬手,轻轻拍打着云想的背 +云想(轻声):程澈。 +程澈:嗯,我在。 +云想:我……不搬了。 +程澈露出“得逞”的笑容 +△云想等了很久,程澈还是没有回应。 +云想:程澈? +△程澈整个人突然向后倒去,云想一惊慌乱的喊着程澈的名字。 +第六十四集: +64-1 场 日 内 程澈房间 +人物:云想、程澈、罐头 +△清晨,云想趴在床边睡着,手还握着程澈的手。 +△程澈缓缓醒来,额头敷着毛巾,看到云想握着自己的手,他看向自己盖的被子,盖了两床被 +子,其中一床是云想的。 +△程澈轻轻挪动姿势侧躺,撑着脑袋看云想,露出微笑 +云想似乎听到动静惊醒。 +云想:你醒了 +程澈:你一直在这? +云想:嗯,你这样我担心你,万一烧傻了怎么办。 +程澈(笑):你回房间睡会吧,我没事儿了。 +云想(摇头):不睡了,我夜里给阿姨打电话了,阿姨等会回来给你输液。 +△云想摸上程澈的额头,然后摸摸自己的额头。 +云想:还是很烫,想不想喝水? +程澈(摇头):别折腾了,哥的身体好着呢。 +云想:你快躺下,程澈!我真的很担心… +程澈(云淡风轻逞英雄):担心什么,又死不了。 +云想看着他沉默半天,小声呢喃 +云想:你要是死了,我就没有靠山了。 +程澈(笑):哦,原来只是怕没有靠山? +云想动了动唇,没说话 +程澈:没良心的,蛋糕白买了。还以为你是担心我。 +云想将脸埋进手臂里,声音闷闷的 +云想:就是在担心你。 +程澈:什么? +云想:什么都没说。 +程澈懒懒地学着云想刚才说的话 +程澈:你说,就是在担心我。 +云想立刻瞪了他一眼。 +程澈:想再听一遍。 +云想:你求我啊。 +程澈:吝啬! +云想:对,我吝啬! +程澈(程澈挑眉,毫不在意,语调慵懒,有些拽):没事儿,我不吝啬。云想,听好,我永远 +是你的靠山。 +云想低下头,不禁鼻尖泛酸,肩膀缩瑟了一下 +程澈:喂,不许哭啊。 +云想:谁要哭啊,我才没有 +△云想想起什么去拿桌子上的合同。 +云想:哦对了,昨天合同我拿回来了。 +程澈:不是,我说了这么多你还是要搬啊?想搬就搬吧,不勉强你。 +云想:真的? +△程澈郁闷的翻身背对云想。 +程澈:嗯。 +云想:我有话要对你说。 +程澈:不听。 +云想:好吧,既然你不想听,那我不说了。 +△云想等了几秒,程澈果然回过头来。 +程澈:说,什么事。 +云想:我本来是想告诉怡姐,我不搬了,但是看到某人这个态度,我还是搬吧,早搬早清净。 +△云想故意说着要去签字。 +程澈:等等! +△程澈坐起来伸手拉住云想,结果太用力把云想直接跌倒在他怀里。 +第六十五集: +65-1 场 日 内 程澈卧室 +人物:云想、程澈 +△云想被程澈稳稳的抱在怀里,两人心中都泛起一阵波澜,氛围有些暧昧。 +云想(小声):程澈。 +程澈:嗯? +云想(突然):我们…靠这么近…会传染的 +△程澈沉默,刚拉起来的氛围被云想一句话打破,云想慌乱的跑出房间,程澈看着她想笑。 +65-2 场 日 外 公交站牌 +人物:云想、程澈 +△第二天上学,两人往公交站牌方向走,途中云想刻意跟程澈拉开距离。 +云想:你就休息了一天,没问题吗? +程澈:没事,好着呢。 +△程澈伸手一把将云想拉到自己身边。 +程澈:你就这么怕我传染你。 +△程澈低头靠近云想,云想立刻捂住口鼻,乖乖点头。 +程澈:我是病毒吗,能毒死你? +云想:这句话好耳熟,不是我的台词嘛。 +△两人来到公交站牌,程澈胳膊自然的搭在云想肩头。 +程澈(装柔弱):唉还是有点浑身无力啊。 +△程澈重量压过去,云想抓着书包带倔强的站直,程澈看着她忍笑。 +程澈(笑):对了,快高考了,你准备考哪所大学?有想法了吗? +云想:去京大吧,我想当个老师,教书育人,程澈,你呢? +△程澈有些为难,他停顿了一下想好措辞才开口。 +程澈:也是京大。 +云想:什么专业呀? +程澈:京都的消防学院。 +△云想若有所思点了点头,没说什么,气氛变得沉重,程澈犹豫了一会再次开口。 +程澈:想想,你介意我未来的职业吗? +云想:为什么介意? +程澈:中消防毕业如果有分配的机会,会分配回到当地,但我不打算这么做,我想像我爸那样 +下基层,也就意味着,我…… +云想:程澈,你怕我因为我爸爸的死抗拒这个职业对吗? +程澈:嗯。 +△蝉鸣四起,风吹起云想裙摆,程澈就这么看着她,过了很久云想才说话。 +云想:如果我说不喜欢,你会怎么做? +△云想看向程澈,四目相对。 +云想:你会放弃你喜欢的职业吗? +△程澈摇摇头。 +云想:那是放弃我? +程澈(着急):云想,这怎么可能,你明知道我不会。 +△云想的发丝被风吹起,她的神情认真平静,声音温柔。 +云想:程澈,一定要在意我的感受吗?就因为我,要抛弃自己的理想和抱负吗? +云想:程澈,我们要一起慢慢变好,你有你的理想,我也有我的抱负,我以后想去山区支教, +这是我从我爸妈去世后就想好的,谁都无法改变!我不要成为谁的负担,谁也不要成为我的绊 +脚石,我们要做的应该是一起努力。 +△程澈神情认真看着云想,她的态度很真诚声音虽然很轻但说的话很有力量。 +程澈:如果非要选择的话,我…… +云想:程澈,我希望你选择你自己。 +△程澈暗暗握拳,心跳加快,眼眶不自觉红了起来。 +云想:程澈,一直坚定地选择你的信仰吧,五星红旗熠熠生辉,我的信仰澄澈明朗 +△云想用另一只手安慰似的拍了拍程澈地脑袋。 +【此处有文案】【文字文案:你是首选,你应该选择你自己,我们都应该为自己的目标奋斗】 +第六十六集: +66-1 场 昏 内 客厅 +人物:云想、程澈、罐头 +△两人回家,罐头朝云想扑过来,经过长时间相处云想已经不那么害怕狗,她蹲下来拍着罐头 +的脑袋,程澈看到眼熟。 +云想:罐头呀有没有想我。 +△云想自然的从口袋拿出火腿肠给罐头吃,罐头尾巴摇的更欢快了。 +程澈:你跟罐头的感情什么时候这么好了? +云想:大概是爱屋及乌吧 +程澈:你这话,算不算是在承认,你… +云想:我表现的不够明显吗? +程澈难以抑制脸上的笑容 +云想:程澈瞧你这点出息 +程澈:别管! +程澈推了推云想 +程澈:从什么时候开始的呀? +云想见他有点飘了,发自内心地想摁住他。 +云想:程澈,我哄哄你,骗小孩呢,你还真信啊? +程澈抬手敲了一下云想的脑袋。 +云想(立刻指向他):好,程澈,你打我,你完了! +程澈(听笑了):怎么个完了法儿? +云想上手就要打回去,被程澈一把止住 +程澈:我让你两条胳膊,我看看你能把我怎样! +云想:那你倒是松手啊 +程澈:你让松就松?我偏不 +两人打闹着气氛温馨欢乐… +【文案大意:我们相互保持默契,在适当的时候沉默,没有把话说破,因为现在还有更重要的 +事,所以我们都在等,等着下一次蝉声再起时,喧闹整个夏天】 +66-2 场 日 内 学校教室 +人物:云想 +△云想在教室的黑板上写着什么,最后走下讲台黑板上写着‘距离高考:100 天’。 +第六十七集: +67-1 场 日 内 学校教室 +人物:云想、程澈、宋谨、洛米、观鹤、同学群众 +△每个同学的书桌上放着高高的书本,他们埋头苦学做题,窗外是骄阳盛夏,蝉鸣不断。 +△广播响起程澈的声音。 +程澈:大家好,我是高三六班的程澈,这是我最后一当校园广播主持,这一年,校园广播站收 +到了 10987 封树洞吐槽信;8090 次点歌。 +△穿插程澈播音画面 +程澈:很开心能陪伴大家走完高三的这段旅程,临近高考,有几句话送给大家。少年应有鸿鹄 +志,当骑骏马踏平川。理想的风会吹进现实,熬过的夜也会变成光指引我们向前。那些沉淀的 +知识,终会照亮我们脚下的路。而我们披星戴月走过的路,必定繁花似锦,万里长空。 +程澈:我说了九个月的明天见。这一次,我没有明天见了,我们顶峰相见。 +△穿插,黑板高考倒计时 +△教室:云想、程澈、主角团做题氛围(白天\黑夜) +阶梯、操场、走廊:云想、程澈背单词 +办公室:云想、洛米拿着试卷向张老师请教问题 +家里:云想、程澈一边吃放一边看着学习资料,爸妈一脸欣慰 +△穿插,黑板高考倒计时最后落到只剩 1 天。 +67-2 场 昏 外 回家路上 +人物:云想、程澈 +△放学回家,两人一起听着 MP3,一起走在回家的路上. +云想:明天就是高考啦,程澈,加油! +程澈:嗯,你也是。 +△云想抬头看着天空深深叹口气,感受晚风带来的凉意。 +△程澈看着云想,犹豫了一会才开口。 +程澈:云想。 +云想(看过去):嗯? +程澈(轻轻):等高中毕业,我们… +云想:去毕业旅行? +程澈:不是… +云想:那去看五月天的演唱会,我特想去 +程澈:不是,我想说的是… +云想(打断):我答应你,只要是…和你在一起 +△程澈的眼神温柔至极,认真的看着她。 +△两人站在路灯下,四目相对。 +程澈:嗯! +【落版文字文案:】 +第六十八集: +68-1 场 昏 内 学校教室 +人物:云想、程澈、宋谨、观鹤、洛米、同学数名 +△用一段 2008 高考前的实事画面(4:3)组成一段关于 2008 年的时代介绍【文案补充】 +△实事画面“报道 2008 年高考结束”(4:3) +△教室内同学们穿着校服拍摄毕业照。(4:3) +洛米:3、2、1 +齐声:毕业快乐! +△同学们把试卷丢向天空(4:3) +△主角团单人镜头特写。 +△云想将试卷扬向空中,满脸欢喜。 +△程澈看着云想露出欣慰的笑容,云想回头两人相视而笑。 +68-2 场 昏 外 天台 +人物:云想、程澈(常服) +△黄昏时分,微风徐徐,天台的长椅上,云想戴着耳机,看着远处的风光 +△程澈走到云想身边轻轻坐下 +△云想望向程澈,两人相视微笑,一同说出 +程澈/云想:毕业快乐 +程澈:给我 +△云想自然的将一边耳机摘下给程澈戴上 +程澈:不是这个 +云想:那你要什么 +程澈:给我个名分 +△云想一愣,假装摇头 +云想:听不懂。 +△云想偏过头看向别处 +△程澈身子侧了侧,出现在云想的视线里,非要让她看着自己。 +程澈:什么听不懂? +云想:就是听不懂你在说什么。 +程澈:好,听不懂是吧?那我就说直接点。 +云想睨着他,垂在腿边的手慢慢攥紧衣衫。 +程澈:我的意思是。 +△程澈疯狂舔唇,肉眼可见的紧张。 +程澈(想了很久,温柔地说):想想,做我女朋友吧。 +△云想没有回应,程澈见她不说话,心里忽然就没底气了。 +程澈:和我在一起,听到没有? +云想(压住了喜悦,沉稳道):我考虑一下。 +程澈:考虑个屁考虑,现在就答应我,说和我在一起,快点!撩都撩了,你现在说考虑一下, +早干嘛去了?不行,必须负责! +△云想听笑了。 +程澈:要拒绝我吗? +△程澈眼尾垂了下来,鼻尖一下子就酸了。 +云想:不拒绝。 +△程澈抬眼,一脸失落,目光委屈地看着她 +程澈:所以呢? +云想:程澈,之所以没有很快回答你。就是希望你知道,我答应和你在一起,是经过深思熟虑 +的。 +△程澈滚了滚喉咙,唇紧抿着,看着她的眼睛慢慢变得明亮。 +云想:程澈,我真的很喜欢你啊。喜欢你的贴心,喜欢你的口是心非。我也希望你是经过深思 +熟虑的想过你喜欢我什么,从哪一刻开始的。 +程澈:从… +△程澈小心翼翼的从包里拿出了什么东西,握住。 +△云想一脸疑惑,程澈的拳头在云想面前摊开,里面是云想的寸照。 +【闪回】 +68-3 日 内 办公室 +人物:程澈、云想、沈宇航 +△云想走过去,沈航宇拿出入学申请表,上面是云想青涩的照片,程澈不自觉歪头看。 +沈航宇:在这上面签个字,然后把你的教科书领走 +△云想点头签上字,程澈注意到云想青涩的照片,露出微笑 +沈航宇 VO:云想,你的书在门后,拿回去吧。 +云想 VO:嗯,谢谢沈老师。 +68-4 夜 内 程澈卧室 +人物:程澈 +△程澈坐在桌前,看着云想的照片,小心翼翼的把它夹在书里 +【穿插男主偷偷喜欢关注女主的画面/文案】 +【闪出】 +68-5 场 昏 外 天台 +人物:云想、程澈(常服) +△云想接过照片,眼眶微微泛红,嘴角不自觉露出笑意 +△程澈睨着云想,突然靠近,吻上她。 +《完》 + diff --git a/doc/参考/改编思路.txt b/doc/参考/改编思路.txt new file mode 100644 index 0000000..7bb86a9 --- /dev/null +++ b/doc/参考/改编思路.txt @@ -0,0 +1,134 @@ +【改编思路.txt - 战略蓝图】 + +==== 核心改编策略 ==== + +【魔改方向】 +将原著温吞的校园恋爱,魔改为"隐藏身份学霸归来,护妻打脸"的极致爽文模式 + +【核心定位】 +- 赛道:校园霸总 + 治愈宠妻 + 逆袭打脸 +- 目标受众:18-35岁女性,偏爱强势男主+被宠女主的组合 +- 情绪商品:"被保护的安全感" + "逆袭打脸的爽感" + "被宠爱的甜腻感" + +==== 节奏调整策略 ==== + +【压缩方案:27集→12集】 +- 第1-3集:开篇即高潮,云想被霸凌+程澈强势护短+身份初露 +- 第4-6集:程澈隐藏实力曝光+全校震惊+宠妻日常 +- 第7-9集:情敌出现+程澈吃醋+霸道宣示主权 +- 第10-12集:最终身份揭晓+公开宠妻+甜蜜结局 + +【节奏铁律】 +- 3秒抓住观众:开篇即冲突 +- 每集2个爽点:打脸+宠溺必须密集投放 +- 5集定CP:第5集必须确立恋爱关系 +- 结尾留钩子:每集结尾必须有"想看下集"的悬念 + +==== 人设强化/魔改方向 ==== + +【程澈 - 隐藏身份学霸霸总】 +原设定:外冷内热学霸 +魔改后: +- 核心标签:"隐藏身份的天才" + "宠妻狂魔" + "护短狂人" +- 隐藏身份:国际奥数冠军/知名企业少东家/天才黑客(三选一) +- 性格极致化:对外人冷酷无情,对云想宠溺到极致 +- 口头禅:"她是我的人" "动她试试" "我的女孩,我来宠" + +【云想 - 被欺凌的灰姑娘】 +原设定:失去父亲的普通女孩 +魔改后: +- 核心标签:"被霸凌的可怜女孩" + "隐藏潜力股" + "逆袭女王" +- 悲惨设定:被继母虐待+校园霸凌+生活困顿 +- 隐藏亮点:学习天赋+音乐才华+善良坚强 +- 成长弧线:从被保护→学会反击→成为程澈的骄傲 + +【配角功能化】 +- 宋谨:程澈的狗腿子+搞笑担当+情报员 +- 观鹤:温柔情敌+推动剧情的工具人 +- 校园恶霸:专门被打脸的反派+突出程澈强大 + +==== 爽点前置与增幅计划 ==== + +【第1集爆点设计】 +- 开场:云想被校园恶霸当众羞辱 +- 爽点1:程澈霸气出场"她是我的人,想动她先过我这关" +- 爽点2:程澈一打三,轻松碾压恶霸 +- 钩子:程澈神秘身份初露端倪 + +【核心爽点类型】 +1. 护短打脸:程澈为云想出头,暴揍反派 +2. 身份震撼:程澈隐藏身份逐步曝光,全校震惊 +3. 宠妻日常:程澈各种花式宠云想,甜到齁 +4. 逆袭反击:云想在程澈帮助下华丽逆袭 +5. 占有宣示:程澈霸道宣示主权,吃醋护妻 + +【爽点密度要求】 +- 每集至少2个大爽点 +- 每3分钟至少1个小甜点 +- 打脸必须有声音,宠爱必须让全世界知道 + +==== 待删除/重大修改的情节 ==== + +【彻底删除】 +- 所有日常琐碎情节(如普通的上课、吃饭场景) +- 过度铺垫的友情线(宋谨、观鹤的戏份大幅压缩) +- 程澈家庭和谐的温馨场面(改为更有戏剧冲突的设定) + +【重大修改】 +- 咖啡店兼职→改为被迫打工还债,增加悲惨色彩 +- 音乐会表演→改为云想被陷害,程澈霸气为她正名 +- 程澈父母→改为开始反对,后被程澈强势说服 + +==== 网络梗语与台词风格 ==== + +【程澈经典台词】 +- "她是我罩的,谁敢动她?" +- "我的女孩,轮不到别人指手画脚" +- "欺负她?你们配吗?" +- "想追我女朋友?先掂量掂量自己几斤几两" + +【云想成长台词】 +- "我不是好欺负的!"(逆袭时刻) +- "程澈,谢谢你让我重新相信光明"(感动时刻) +- "我要变强,站在你身边"(成长宣言) + +【网络梗语植入】 +- "这就是传说中的霸总吗?爱了爱了" +- "程澈:我摊牌了,我就是来宠妻的" +- "云想:我可以,但我的男朋友不可以" + +==== 预期商业效果 ==== + +【数据目标】 +- 完播率:提升至65%以上 +- 付费转化率:提升至8%以上 +- 用户留存:3日留存率60%以上 + +【市场定位】 +对标成功案例:《我在他乡挺好的》+《你是我的荣耀》的校园版 +预期排名:同类型短剧TOP10 + +==== 执行原则 ==== + +1. **极致化原则**:所有人设、情节、情绪都要放大100倍 +2. **密集化原则**:爽点密度必须达到每3分钟1个 +3. **标签化原则**:每个角色都要有清晰的标签,3秒内让观众记住 +4. **情绪化原则**:每个情节都要服务于观众的情绪体验 +5. **商业化原则**:一切改编都要服务于完播率和付费率 + +==== 风险控制 ==== + +【潜在风险】 +- 改编幅度过大,可能失去原著精髓 +- 爽点过于密集,可能造成审美疲劳 + +【应对策略】 +- 保留核心情感线不变,只改变表达方式 +- 在爽点之间穿插温情时刻,形成情绪节奏 + +==== 总结 ==== + +这份战略蓝图将指导我们将一个温吞的校园恋爱故事,改造成具有强烈商业价值的爆款短剧。通过人设极致化、节奏密集化、爽点前置化,我们有信心打造出一部让观众"停不下来"的短剧作品。 + +改编成功率预估:90% +市场表现预期:A+级(头部10%) \ No newline at end of file diff --git a/doc/参考/核心人物小传.txt b/doc/参考/核心人物小传.txt new file mode 100644 index 0000000..69845ef --- /dev/null +++ b/doc/参考/核心人物小传.txt @@ -0,0 +1,268 @@ +【核心人物小传.txt - 剧本圣经】 + +==== 主角人设档案 ==== + +【程澈 - 隐藏身份的宠妻学霸霸总】 + +基础信息: +- 年龄:18岁,高三学生 +- 外貌:185cm,五官深邃,气质冷峻中带着贵气 +- 家庭:程氏集团继承人,家境优渥但低调 +- 学业:年级第一,国际奥数冠军,天才黑客 + +核心人设标签: +1. **隐藏身份的天才**:表面普通学生,实际是商业帝国继承人 +2. **宠妻狂魔**:对云想无底线宠爱,为她可以放弃一切 +3. **护短狂人**:谁敢欺负云想,他就跟谁拼命 +4. **毒舌傲娇**:嘴硬心软,明明在乎却不肯直说 + +性格特征: +- 对外:冷漠高傲,生人勿近,说话毒舌但有分寸 +- 对云想:温柔体贴,无微不至,占有欲极强 +- 处事风格:雷厉风行,绝不拖泥带水 +- 底线:绝不允许任何人伤害云想 + +经典台词库: +- "她是我的人,想动她先过我这关" +- "我的女孩,轮不到别人指手画脚" +- "欺负她?你们配吗?" +- "我可以放弃一切,但不能放弃她" +- "伤害她,就是与我为敌" +- "云想是我的女朋友,我的未来妻子" + +隐藏身份层次: +第一层:学霸(公开) +第二层:国际奥数冠军(第4集曝光) +第三层:程氏集团继承人(第9集曝光) +第四层:天才黑客(第9集曝光) + +成长弧线: +初期:冷漠学霸,对一切漠不关心 +中期:因云想开始有了软肋,学会关心他人 +后期:为了爱情敢于对抗家族,成为真正的男人 + +宠妻技能包: +- 记住云想的所有喜好和习惯 +- 为云想准备爱心早餐和小惊喜 +- 在云想面前秒变温柔,反差萌满分 +- 霸道护短,绝不让云想受委屈 +- 用实际行动证明爱意,不只是嘴上说说 + +弱点与软肋: +- 云想是他唯一的软肋,为了她可以不顾一切 +- 不善于表达情感,经常嘴硬心软 +- 对家族期望有压力,但最终选择爱情 + +--- + +【云想 - 逆袭成长的治愈系女主】 + +基础信息: +- 年龄:17岁,高三学生 +- 外貌:165cm,清纯可爱,笑容治愈 +- 家庭:父亲去世,与继母关系冷淡,经济困难 +- 特长:音乐天赋,学习能力强,内心坚强 + +核心人设标签: +1. **被欺凌的灰姑娘**:出身贫寒,经常被同学看不起 +2. **隐藏潜力股**:拥有音乐天赋和学习能力,只是缺乏机会 +3. **治愈系天使**:善良纯真,能够温暖他人内心 +4. **逆袭女王**:在程澈帮助下华丽蜕变,成为自信女孩 + +性格特征: +- 表面:温柔善良,有些自卑,但内心坚强 +- 内在:聪明敏感,有主见,不愿意一直被保护 +- 处事风格:以德报怨,用善良化解恶意 +- 成长目标:想要变强,配得上程澈 + +经典台词库: +- "程澈,谢谢你让我重新相信光明" +- "我要变强,站在你身边" +- "我不是好欺负的!"(逆袭时刻) +- "程澈,我想试着配得上你" +- "我可以,但我的男朋友不可以" + +悲惨设定: +- 父亲去世,失去依靠 +- 继母冷漠,缺乏家庭温暖 +- 经济困难,需要兼职维持生活 +- 校园霸凌,经常被同学欺负 +- 自卑心理,觉得自己配不上优秀的人 + +隐藏亮点: +- 音乐天赋:拥有绝对音感,歌声动人 +- 学习能力:一旦认真起来,成绩提升很快 +- 善良品格:即使被欺负也不记仇,以德报怨 +- 坚强意志:面对困难从不轻易放弃 +- 治愈能力:能够温暖他人,给人希望 + +成长弧线: +初期:自卑怯懦,被动接受欺凌 +中期:在程澈保护下逐渐自信,开始反击 +后期:华丽蜕变,成为自信独立的女王 + +逆袭技能包: +- 音乐才华爆发,一鸣惊人 +- 学习成绩突飞猛进 +- 气质蜕变,从灰姑娘到公主 +- 学会反击,不再被动挨打 +- 获得大家认可和尊重 + +内心独白风格: +- "他为什么对我这么好?我配得上吗?" +- "我要努力变优秀,不能一直被保护" +- "程澈就像一束光,照亮了我的世界" + +--- + +==== 重要配角人设 ==== + +【宋谨 - 程澈的忠实狗腿子】 + +基础信息: +- 年龄:18岁,程澈的死党 +- 性格:活泼搞笑,忠诚可靠 +- 作用:搞笑担当,情报员,推动剧情 + +核心标签: +- 程澈的头号迷弟 +- 云想的护花使者 +- 全剧的搞笑担当 + +经典台词: +- "澈哥,你这是动真格的啊" +- "想想,我也会保护你的!" +- "快走快走,我感觉到周围涌起杀意" + +功能定位: +- 烘托程澈的魅力 +- 为云想提供友情支持 +- 在关键时刻提供帮助 +- 调节剧情氛围 + +--- + +【观鹤 - 温柔情敌】 + +基础信息: +- 年龄:18岁,学生会主席 +- 外貌:温文尔雅,阳光帅气 +- 性格:温柔体贴,善解人意 + +核心标签: +- 温柔情敌 +- 完美男神 +- 推动剧情的工具人 + +作用: +- 让程澈吃醋,推动感情线 +- 衬托程澈的独特魅力 +- 在关键时刻帮助主角 + +经典台词: +- "程澈,我会对妹妹好的" +- "想想,你值得被更好地对待" + +--- + +【林雅 - 程澈的未婚妻】 + +基础信息: +- 年龄:18岁,豪门千金 +- 外貌:高贵冷艳,气场强大 +- 性格:高傲任性,但不坏 + +核心标签: +- 豪门千金 +- 强势情敌 +- 最终和解的对手 + +作用: +- 制造情感危机 +- 考验主角感情 +- 推动剧情高潮 + +成长弧线: +初期:高傲看不起云想 +中期:被云想的品格感动 +后期:主动退出,成全两人 + +--- + +【程枭 - 程澈的父亲】 + +基础信息: +- 年龄:45岁,程氏集团董事长 +- 性格:严厉但爱子,商人本色 +- 态度:从反对到接受云想 + +核心标签: +- 严父慈心 +- 商业巨头 +- 最终的支持者 + +作用: +- 制造家族压力 +- 考验程澈的决心 +- 最终认可云想 + +--- + +【校园恶霸团 - 反派工具人】 + +基础设定: +- 专门欺负弱小的校园霸凌者 +- 看不起云想的出身 +- 被程澈轻松碾压的背景板 + +作用: +- 突出云想的可怜 +- 展现程澈的强大 +- 提供打脸爽点 + +==== 人物关系网络 ==== + +【核心三角关系】 +程澈 ←→ 云想 ←→ 观鹤 +(保护) (暗恋) + +【家族关系】 +程枭(父亲)→ 程澈 ←→ 林雅(未婚妻) +(压力) (联姻) + +【友情关系】 +宋谨 → 程澈 & 云想 +(支持) + +【对立关系】 +校园恶霸 ←→ 云想 ←→ 程澈 +(欺凌) (保护) + +==== 人设运用原则 ==== + +1. **标签化表达**:每个角色都有清晰的标签,3秒内让观众记住 +2. **功能性明确**:每个角色都有明确的剧情功能,不做无用功 +3. **反差萌设计**:程澈的冷酷vs宠妻,云想的柔弱vs坚强 +4. **成长弧线**:主角必须有明显的成长变化 +5. **情感真实**:在极致化的同时保持情感的可信度 + +==== 台词风格指南 ==== + +【程澈台词特点】 +- 霸道直接,不拐弯抹角 +- 护妻时语气强硬,对云想时语气温柔 +- 多用短句,有力度 +- 经常用"我的女孩""我的人"等占有性词汇 + +【云想台词特点】 +- 温柔善良,但逐渐变得有力量 +- 成长过程中台词越来越自信 +- 多用疑问句表达内心不确定 +- 感谢和道歉用词较多 + +【配角台词特点】 +- 宋谨:搞笑幽默,多用网络用语 +- 观鹤:温文尔雅,书面语较多 +- 林雅:高傲冷艳,用词尖锐 + +这份人物小传将确保我们的角色立体饱满,每个人都有鲜明的个性和明确的功能,为后续的剧本创作提供坚实的基础。 \ No newline at end of file diff --git a/doc/参考/核心大纲.txt b/doc/参考/核心大纲.txt new file mode 100644 index 0000000..c4d5d77 --- /dev/null +++ b/doc/参考/核心大纲.txt @@ -0,0 +1,285 @@ +【核心大纲.txt - 剧本圣经】 + +==== 总体架构 ==== + +【改编原则】严格遵循《改编思路.txt》战略蓝图 +【总集数】12集(每集8-10分钟) +【核心主线】隐藏身份学霸护妻打脸 + 灰姑娘逆袭成长 +【情感主线】从保护到依赖到平等的爱情成长线 + +==== 三幕结构 ==== + +【第一幕:相遇与保护】(第1-4集) +核心任务:建立人设,制造冲突,确立保护关系 + +【第二幕:成长与考验】(第5-8集) +核心任务:身份揭晓,情感升温,面临考验 + +【第三幕:逆袭与圆满】(第9-12集) +核心任务:最终逆袭,公开关系,甜蜜结局 + +==== 分集详细大纲 ==== + +【第1集:霸气出场,一见钟情】 +开场爆点:云想被校园恶霸当众羞辱 +- 场景:学校食堂,云想被泼汤,众人围观嘲笑 +- 恶霸台词:"孤儿就该有孤儿的样子,别装清高" + +程澈出场:霸气护短,一打三 +- 经典台词:"她是我的人,想动她先过我这关" +- 动作戏:程澈轻松制服三个恶霸,全场震惊 + +身份暗示:程澈神秘背景初露 +- 细节:程澈接到神秘电话,对方恭敬称呼"少爷" +- 钩子:云想好奇程澈真实身份 + +爽点密度:护短打脸 + 英雄救美 + 身份悬念 +结尾钩子:程澈对云想说"以后跟着我,没人敢欺负你" + +【第2集:宠妻日常,甜蜜互动】 +程澈宠妻模式开启 +- 场景1:程澈为云想准备爱心早餐,全班女生嫉妒 +- 场景2:云想被老师刁难,程澈霸气为她出头 +- 场景3:程澈送云想回家,温柔细节满分 + +云想内心变化 +- 独白:"他为什么对我这么好?我配得上吗?" +- 行动:开始努力学习,想要配得上程澈 + +配角推动剧情 +- 宋谨:"澈哥,你这是动真格的啊" +- 观鹤:温柔出场,成为潜在情敌 + +爽点密度:宠妻日常 + 甜蜜互动 + 情敌出现 +结尾钩子:观鹤对云想表达好感,程澈吃醋 + +【第3集:吃醋护妻,霸道宣示】 +程澈吃醋大戏 +- 场景:观鹤邀请云想参加音乐社,程澈脸色阴沉 +- 霸道台词:"我的女孩,轮不到别人指手画脚" +- 行动:程澈强势阻止,当众宣示主权 + +云想困惑与成长 +- 内心戏:对程澈的占有欲既甜蜜又困惑 +- 行动:主动询问程澈真实想法 + +身份线推进 +- 细节:程澈轻松解决学校技术难题,展现天才实力 +- 暗示:有人调查程澈背景,发现不简单 + +爽点密度:吃醋护妻 + 霸道宣示 + 天才展现 +结尾钩子:神秘人出现,要揭露程澈身份 + +【第4集:身份初露,全校震惊】 +程澈天才身份曝光 +- 爆点:程澈是国际奥数冠军的身份被曝光 +- 反应:全校师生震惊,云想不敢置信 +- 台词:"原来我喜欢的人这么优秀" + +云想自卑与逃避 +- 心理:觉得自己配不上程澈,开始逃避 +- 行动:故意疏远程澈,让他难受 + +程澈追妻模式 +- 霸道台词:"我选择了你,就不会放手" +- 行动:各种花式追妻,甜蜜攻势 + +爽点密度:身份震撼 + 追妻日常 + 甜蜜攻势 +结尾钩子:云想决定努力变优秀,配得上程澈 + +【第5集:确立关系,甜蜜升级】 +云想主动出击 +- 场景:云想为程澈准备惊喜,表达心意 +- 台词:"程澈,我想试着配得上你" +- 行动:两人正式确立恋爱关系 + +甜蜜日常升级 +- 场景1:程澈教云想学习,亲密互动 +- 场景2:两人一起参加学校活动,撒糖不断 +- 场景3:程澈为云想庆祝生日,浪漫满分 + +新的威胁出现 +- 反派:程澈的未婚妻出现,要拆散两人 +- 冲突:家族联姻的压力,程澈面临选择 + +爽点密度:确立关系 + 甜蜜日常 + 新威胁 +结尾钩子:程澈未婚妻强势出场,要云想离开 + +【第6集:情敌来袭,关系考验】 +程澈未婚妻登场 +- 人设:富家千金,高傲冷艳,实力强劲 +- 台词:"你一个孤儿,凭什么跟我抢程澈?" +- 行动:用金钱和权势威胁云想 + +云想受到打击 +- 心理:再次陷入自卑,觉得自己不配 +- 行动:为了程澈的前途,选择默默离开 + +程澈愤怒反击 +- 霸道台词:"我的女人,谁都不能动" +- 行动:公开拒绝未婚妻,选择云想 + +爽点密度:情敌对决 + 程澈护妻 + 霸道选择 +结尾钩子:程澈家族施压,要断绝父子关系 + +【第7集:家族压力,坚定选择】 +程澈家族施压 +- 场景:程澈父亲出场,要求分手 +- 威胁:断绝关系,取消继承权 +- 程澈回应:"我可以放弃一切,但不能放弃她" + +云想成长蜕变 +- 觉醒:决定不再逃避,要为爱情而战 +- 行动:努力提升自己,证明自己的价值 +- 台词:"我要变强,站在你身边" + +甜蜜坚持 +- 场景:两人面对压力,更加珍惜彼此 +- 互动:程澈承诺永远保护云想 +- 成长:云想开始展现自己的才华 + +爽点密度:家族对抗 + 坚定选择 + 成长蜕变 +结尾钩子:云想隐藏的音乐天赋被发现 + +【第8集:天赋觉醒,华丽逆袭】 +云想音乐天赋爆发 +- 场景:学校音乐比赛,云想一鸣惊人 +- 反应:全校震惊,刮目相看 +- 台词:"原来她这么有才华" + +程澈骄傲宠妻 +- 表现:为云想的表现感到骄傲 +- 台词:"这就是我的女孩,我的骄傲" +- 行动:高调为云想庆祝 + +反派受挫 +- 未婚妻:开始正视云想的实力 +- 家族:对云想的态度开始转变 +- 恶霸:彻底被云想的逆袭打脸 + +爽点密度:天赋觉醒 + 华丽逆袭 + 打脸反派 +结尾钩子:更大的危机即将来临 + +【第9集:最大危机,生死考验】 +程澈真实身份完全曝光 +- 身份:国际知名企业继承人 + 天才黑客 +- 危机:商业对手绑架云想,威胁程澈 +- 选择:程澈面临事业与爱情的终极选择 + +云想生死时刻 +- 危险:被绑架,生命受到威胁 +- 成长:在危机中展现坚强和智慧 +- 信念:相信程澈一定会来救她 + +程澈英雄救美 +- 行动:动用所有资源营救云想 +- 台词:"伤害她,就是与我为敌" +- 结果:成功救出云想,消除威胁 + +爽点密度:身份震撼 + 生死营救 + 英雄救美 +结尾钩子:经历生死,两人感情更加坚定 + +【第10集:公开关系,甜蜜宣示】 +程澈公开宣示 +- 场景:学校大会,程澈公开表白 +- 台词:"云想是我的女朋友,我的未来妻子" +- 反应:全校轰动,羡慕嫉妒恨 + +家族认可 +- 转变:程澈父母被云想的品格感动 +- 接纳:正式接受云想进入家族 +- 台词:"欢迎你,我们的儿媳妇" + +云想完美蜕变 +- 成长:从自卑女孩到自信女王 +- 成就:在音乐和学业上都有突破 +- 地位:成为学校的风云人物 + +爽点密度:公开宣示 + 家族认可 + 完美蜕变 +结尾钩子:两人开始规划美好未来 + +【第11集:甜蜜日常,幸福满溢】 +校园甜蜜日常 +- 场景1:程澈云想成为学校最受瞩目的情侣 +- 场景2:两人一起参加各种活动,撒糖不断 +- 场景3:程澈继续宠妻,云想越来越自信 + +未来规划 +- 讨论:两人规划大学和未来的计划 +- 承诺:程澈承诺给云想最好的未来 +- 成长:云想也有了自己的事业规划 + +小插曲解决 +- 情节:解决之前所有的遗留问题 +- 和解:与之前的对手达成和解 +- 圆满:所有人都为两人祝福 + +爽点密度:甜蜜日常 + 未来规划 + 圆满和解 +结尾钩子:毕业典礼即将到来 + +【第12集:完美结局,永远幸福】 +毕业典礼 +- 场景:学校毕业典礼,两人双双获得荣誉 +- 成就:程澈保送名校,云想获得音乐奖学金 +- 台词:"我们一起创造了奇迹" + +终极表白 +- 场景:程澈在毕业典礼上求婚 +- 台词:"云想,嫁给我,让我宠你一辈子" +- 结果:云想含泪答应,全场祝福 + +美好未来 +- 展望:两人携手走向美好未来 +- 成长:从保护与被保护到平等相爱 +- 寓意:真爱能让人成为更好的自己 + +爽点密度:毕业荣誉 + 浪漫求婚 + 美好未来 +完美结局:"从此王子和公主过上了幸福的生活" + +==== 核心爽点统计 ==== + +【护短打脸】:第1、3、6、9集 +【身份震撼】:第1、4、9集 +【宠妻日常】:第2、5、7、11集 +【逆袭反击】:第4、8、10集 +【占有宣示】:第3、6、10集 +【甜蜜互动】:第2、5、7、11、12集 + +总计爽点:30个(平均每集2.5个) + +==== 情感节奏控制 ==== + +【情感起伏曲线】 +第1-2集:快速升温(相遇到心动) +第3-4集:小波折(吃醋到身份曝光) +第5集:情感高峰(确立关系) +第6-7集:重大考验(情敌和家族压力) +第8集:逆袭高光(天赋觉醒) +第9集:危机低谷(生死考验) +第10-12集:圆满结局(公开到求婚) + +【观众情绪设计】 +愤怒→心疼→甜蜜→紧张→骄傲→担心→感动→幸福 + +==== 商业化考量 ==== + +【付费点设置】 +- 第3集:程澈吃醋大戏(情感高潮) +- 第6集:情敌对决(冲突高潮) +- 第9集:生死营救(剧情高潮) +- 第12集:浪漫求婚(完美结局) + +【完播率保障】 +- 每集结尾强钩子,制造"必须看下集"的冲动 +- 爽点密集分布,确保观众情绪始终在线 +- 甜蜜与虐心交替,形成情绪过山车 + +==== 执行要点 ==== + +1. **严格控制节奏**:每3分钟必须有一个情绪点 +2. **突出人设标签**:程澈的"宠妻",云想的"成长" +3. **强化视觉冲击**:打斗、表白、求婚等场面要有仪式感 +4. **网络语言植入**:符合当下年轻人的表达习惯 +5. **情感真实性**:在极致化的同时保持情感的真实可信 + +这份大纲将确保我们的改编既有商业价值,又有情感深度,打造出真正的爆款短剧。 \ No newline at end of file diff --git a/doc/参考/第1-3集剧本.txt b/doc/参考/第1-3集剧本.txt new file mode 100644 index 0000000..f959836 --- /dev/null +++ b/doc/参考/第1-3集剧本.txt @@ -0,0 +1,412 @@ +【第1-3集剧本 - 开篇即高潮版】 + +==== 第1集:霸气出场,护妻打脸 ==== + +【开场爆点 - 3秒抓住观众】 + +1-1 场 日 内 学校食堂 +人物:云想、校园恶霸(刀疤、胖子、瘦猴)、围观学生 + +△食堂嘈杂,云想端着餐盘小心翼翼找位置 +△云想穿着洗得发白的校服,背着补丁书包,显得格格不入 + +刀疤(故意撞向云想):哎呀,不好意思啊~ + +△餐盘翻倒,热汤泼在云想身上,围观学生哄笑 + +胖子:孤儿院出来的就是不一样,连走路都不会 +瘦猴:听说还是被人不要的野种,啧啧啧 +刀疤:在我们学校混,得懂规矩。每天交50块保护费,不然... + +△云想咬牙忍受,默默蹲下收拾餐具 +△围观学生拿手机拍摄,议论纷纷 + +学生甲:又是那个转校生,真可怜 +学生乙:听说住在程澈家,不知道什么关系 +学生丙:程澈?那个冰山学霸? + +【程澈霸气出场 - 英雄救美升级版】 + +△突然,食堂安静下来 +△程澈缓缓走来,周围学生自动让路 +△程澈穿着定制校服,气场强大,眼神冷冽 + +程澈(声音低沉,充满威胁):谁允许你们动她的? + +刀疤(色厉内荏):程澈,这不关你事吧?我们只是... + +△程澈一把抓住刀疤衣领,轻松将其提起 + +程澈(眼神杀气腾腾):她是我的人。想动她,先过我这关。 + +△全场震惊,云想抬头看向程澈,眼中闪过惊讶 + +胖子(壮胆):程澈,你别太嚣张!我们三个... + +△程澈反手一推,胖子撞翻三张桌子 +△瘦猴想偷袭,被程澈一个过肩摔放倒 +△整个过程不到10秒,干净利落 + +程澈(居高临下):以后见到她,绕道走。否则,后果自负。 + +△三个恶霸狼狈逃窜 +△程澈转身,温柔地看向云想 + +程澈(语气瞬间变温柔):没事吧? + +△云想呆呆点头,还没从震惊中回过神 + +程澈(霸道宣言):记住,从今天开始,你在这个学校,没人敢欺负你。 + +△程澈脱下外套,披在云想身上 +△围观学生窃窃私语,拍照录像 + +学生甲:我的天,程澈居然为了她出手! +学生乙:这是什么神仙爱情? +学生丙:云想到底什么来头? + +【身份暗示 - 制造悬念】 + +1-2 场 日 外 学校走廊 +人物:程澈、云想、宋谨(远观) + +△程澈的手机响起,来电显示:"管家" + +程澈(接电话,语气恭敬):什么事? +管家(电话):少爷,董事会那边催您回去处理文件 +程澈:知道了,晚上再说 +管家:是,少爷 + +△云想偷听到对话,疑惑地看向程澈 +△程澈挂断电话,发现云想在看自己 + +程澈(解释):家里的事 +云想(小声):谢谢你刚才... +程澈(打断):不用谢。以后跟着我,没人敢动你。 + +△宋谨从远处跑来 + +宋谨:澈哥!刚才那一幕太帅了!全校都传疯了! +程澈(皱眉):传什么? +宋谨:说你为了保护云想,一打三!现在大家都在猜云想的身份! + +△程澈看向云想,眼神复杂 + +程澈:走吧,我送你回教室 + +【第1集结尾钩子】 + +1-3 场 日 内 教室 +人物:云想、同学们 + +△云想走进教室,所有人的目光都聚焦在她身上 +△窃窃私语声此起彼伏 + +同学甲:就是她,程澈的女人 +同学乙:听说程澈为了她,把刀疤他们打得很惨 +同学丙:她到底什么背景? + +△云想坐下,拿出手机,收到一条短信 +△短信内容:"小心点,这只是开始。- 匿名" +△云想脸色一变,紧张地四处张望 + +云想(OS):程澈为什么要保护我?他的真实身份是什么?还有这条短信... + +△镜头拉远,云想坐在教室里,显得孤单而脆弱 +△但她的眼神中,第一次出现了一丝希望的光芒 + +【第1集完】 + +==== 第2集:宠妻日常,甜蜜暴击 ==== + +【开场回顾 + 新冲突】 + +2-1 场 晨 外 学校门口 +人物:云想、程澈、林雅(新角色) + +△云想独自走向学校,路过的学生都在指指点点 +△突然,一辆粉色玛莎拉蒂停在她面前 +△车门打开,走出一个穿着名牌的漂亮女孩 - 林雅 + +林雅(高傲地打量云想):你就是云想? +云想(警惕):你是? +林雅:我是林雅,程澈的未婚妻 + +△云想震惊,后退一步 + +林雅(冷笑):看来程澈没告诉你。我们两家早就定了娃娃亲 +云想:我和程澈没有... +林雅(打断):识相的话,离他远点。你一个孤儿,配不上他 + +△正在此时,程澈出现 + +程澈(冷声):林雅,你在干什么? +林雅(撒娇):澈哥哥,我只是想认识一下妹妹 +程澈(看向云想):她有没有为难你? + +△云想摇头,不想惹麻烦 + +程澈(对林雅):以后不许接近她 +林雅(不甘心):澈哥哥,你为了一个外人... +程澈(冷漠):她不是外人,她是我要保护的人 + +△林雅脸色难看,开车离去 + +【宠妻模式全开】 + +2-2 场 日 内 教室 +人物:程澈、云想、老师、同学们 + +△上课时间,云想在认真听讲 +△数学老师故意刁难云想 + +数学老师:云想,你来解这道题 +△黑板上是一道超纲的奥数题 +云想(紧张):老师,这道题我... +数学老师(冷笑):不会就说不会,别浪费大家时间 + +△同学们开始窃笑 +△程澈突然站起来 + +程澈(冷声):老师,这道题超出了高二教学范围 +数学老师:程澈,你什么意思? +程澈:我的意思是,如果您要考察学生,请出符合教学大纲的题目 + +△程澈走到黑板前,快速解出答案 + +程澈:这道题的解法有三种,我刚才用的是最简单的一种 + +△全班震惊,数学老师脸色难看 + +程澈(回到座位,对云想):以后有人为难你,直接告诉我 + +【午餐时光 - 甜蜜互动】 + +2-3 场 日 内 学校天台 +人物:程澈、云想、宋谨 + +△程澈带着精美的便当盒出现 + +程澈:过来,吃饭 +云想:我有带饭... +程澈(打开便当盒):我让人准备的,营养搭配 + +△便当盒里是精致的日式料理 +△云想看得眼睛发亮 + +宋谨(惊讶):澈哥,你什么时候这么贴心了? +程澈(瞪他一眼):闭嘴 + +△程澈亲自给云想夹菜 + +程澈:多吃点,你太瘦了 +云想(脸红):谢谢... +程澈:不用跟我客气 + +△宋谨在旁边吃狗粮,表情夸张 + +宋谨:我感觉空气中都是恋爱的酸臭味 +程澈:再废话,你的饭没了 +宋谨:我错了,澈哥! + +【放学护送 - 温柔细节】 + +2-4 场 黄昏 外 回家路上 +人物:程澈、云想 + +△程澈骑着摩托车,云想坐在后座 +△夕阳西下,两人的影子拉得很长 + +程澈:抓紧我 +云想(害羞):嗯... + +△云想小心翼翼地抓住程澈的衣角 +△程澈感受到她的紧张 + +程澈:抓紧点,不然会摔下去 + +△云想只好环抱住程澈的腰 +△程澈嘴角微微上扬 + +程澈:以后每天我来接你 +云想:不用麻烦你... +程澈:不麻烦。我说过,我会保护你 + +△路过花店,程澈突然停车 + +程澈:等我一下 + +△程澈进入花店,买了一束白玫瑰 +△回来递给云想 + +程澈:送你的 +云想(惊喜):为什么? +程澈:没有为什么,喜欢就收下 + +△云想接过花,眼中闪烁着泪光 + +云想:从来没有人送过我花... +程澈(心疼):以后会有的 + +【第2集结尾钩子】 + +2-5 场 夜 内 云想房间 +人物:云想 + +△云想将白玫瑰插在水瓶里 +△拿出手机,又收到匿名短信 +△短信内容:"享受吧,这种日子不会太久。程澈的真实身份,你永远想不到。" +△云想皱眉,回复:"你是谁?" +△对方秒回:"一个知道真相的人。想知道程澈为什么保护你吗?" + +云想(OS):程澈到底隐瞒了什么?他为什么对我这么好? + +△云想看向窗外,程澈房间的灯还亮着 +△她想起今天的种种温柔,心中五味杂陈 + +【第2集完】 + +==== 第3集:身份初露,情感升温 ==== + +【开场危机】 + +3-1 场 日 外 学校后门 +人物:云想、神秘男子、程澈 + +△云想独自走向学校后门 +△突然被几个陌生男子包围 + +神秘男子甲:云想小姐,有人想见你 +云想(害怕):你们是谁?我不认识你们 +神秘男子乙:别害怕,只是聊聊 + +△男子们逼近,云想后退 +△正在危急时刻,程澈出现 + +程澈(冷声):放开她 +神秘男子甲:程少爷,我们只是奉命... +程澈(打断):我说,放开她 + +△程澈眼神冰冷,身上散发出强大的威压 +△神秘男子们对视一眼,竟然真的退开了 + +神秘男子甲:程少爷,老板说了,这件事迟早要解决 +程澈:告诉你们老板,想动她,先问过我 + +△男子们离去 +△云想震惊地看着程澈 + +云想:他们叫你什么?程少爷? +程澈(避开话题):没事了,我送你进去 + +【宋谨爆料 - 身份暗示】 + +3-2 场 日 内 学校图书馆 +人物:云想、宋谨 + +△云想在图书馆学习,宋谨偷偷坐到她旁边 + +宋谨(神秘兮兮):想想,你想知道澈哥的真实身份吗? +云想(好奇):什么意思? +宋谨:你知道程氏集团吗? +云想:知道啊,很大的公司 +宋谨:澈哥就是程氏集团的少东家 + +△云想震惊,书掉在地上 + +云想:你开玩笑的吧? +宋谨:我骗你干嘛?他爸程枭是程氏集团的董事长 +云想:那他为什么要隐瞒? +宋谨:可能是想体验普通人的生活吧。不过... + +△宋谨欲言又止 + +云想:不过什么? +宋谨:不过他从来没有为了哪个女孩这么上心过 + +△云想脸红,心跳加速 + +【程澈主动表白 - 情感升温】 + +3-3 场 黄昏 外 学校天台 +人物:程澈、云想 + +△程澈约云想到天台 +△夕阳西下,城市灯火初上 + +程澈:有些话,我想对你说 +云想(紧张):什么话? +程澈:关于我的身份,你应该已经知道了 +云想:宋谨告诉我的... +程澈:我没有故意隐瞒,只是不想你有压力 + +△程澈走近云想 + +程澈:云想,我想问你一个问题 +云想:什么? +程澈:如果我不是程氏集团的少爷,只是一个普通学生,你还会接受我的保护吗? + +△云想愣住,看着程澈认真的眼神 + +云想:为什么这么问? +程澈:因为我希望你喜欢的是我这个人,而不是我的身份 + +△云想心中一暖 + +云想:程澈,你为什么要保护我? +程澈(深情):因为从第一眼看到你,我就知道,我不能让任何人伤害你 + +△两人四目相对,空气中弥漫着暧昧 + +程澈:云想,做我女朋友好吗? + +△云想震惊,脸红得像苹果 + +云想:我...我... +程澈(温柔):不用急着回答,我等你 + +【第3集结尾钩子 - 危机再现】 + +3-4 场 夜 内 云想房间 +人物:云想 + +△云想躺在床上,回想着程澈的表白 +△手机突然响起,是陌生号码 + +神秘声音:云想,考虑清楚了吗? +云想:你到底是谁?想要什么? +神秘声音:我要的很简单,离开程澈 +云想:为什么? +神秘声音:因为你的存在,会害死他 + +△电话挂断,云想惊恐地坐起来 + +云想(OS):害死他?这是什么意思? + +△窗外突然传来摩托车声 +△云想看向窗外,程澈正在楼下等她 +△程澈抬头看向她的窗户,温柔地挥手 +△云想内心挣扎,既想跑下去,又害怕会害了他 + +【第3集完】 + +==== 创作说明 ==== + +【改编亮点】 +1. **开篇即高潮**:第1集直接从霸凌事件开始,3秒抓住观众 +2. **人设极致化**:程澈从温和学霸变成霸道护妻狂魔 +3. **爽点密集**:每集至少2个打脸/宠溺场面 +4. **悬念设置**:神秘身份+威胁短信+匿名电话层层递进 +5. **情感升温**:从保护到表白,节奏紧凑 + +【商业化考量】 +1. **完播率**:每集结尾都有强烈钩子 +2. **付费点**:程澈身份揭晓、表白场面、危机解决 +3. **话题性**:霸总护妻、校园霸凌、身份悬疑 +4. **代入感**:云想从被欺凌到被宠爱的逆袭 + +【与原著对比】 +- 原著27集内容压缩至3集 +- 删除大量日常铺垫,直奔主题 +- 强化冲突对立,增加戏剧张力 +- 人物关系更加极致化和标签化 \ No newline at end of file diff --git a/doc/参考/第10-12集剧本.txt b/doc/参考/第10-12集剧本.txt new file mode 100644 index 0000000..e4075f0 --- /dev/null +++ b/doc/参考/第10-12集剧本.txt @@ -0,0 +1,491 @@ +【第10-12集剧本 - 终极对决,完美结局】 + +==== 第10集:身份揭秘,终极对决 ==== + +【神秘敌人现身】 + +10-1 场 日 内 程氏集团董事会 +人物:程澈、程枭、董事们、神秘人(程澈的叔叔程威) + +△程澈正在主持董事会 +△突然,一个中年男子走进会议室 + +程威:各位董事,不好意思打扰了 +程澈(震惊):二叔?你不是在国外吗? +程威:我回来了,而且带来了一个好消息 +程枭:什么好消息? +程威:我要重新夺回程氏集团的控制权 + +△全场哗然 + +程澈:二叔,你在说什么? +程威:澈儿,你还太年轻,不适合管理这么大的企业 +程澈:是你在背后搞鬼? +程威:包括陈总的事情,都是我安排的 + +△程威拿出一份文件 + +程威:这是你父亲当年的遗嘱,真正的遗嘱 +程澈:不可能! +程威:上面写得很清楚,如果你在25岁之前结婚,就失去继承权 + +【云想的抉择】 + +10-2 场 日 内 学校教室 +人物:云想、观鹤、宋谨 + +△宋谨匆忙找到云想 + +宋谨:想想,澈哥出事了! +云想:什么事? +宋谨:他的叔叔回来了,要夺走程氏集团 +观鹤:怎么会这样? +宋谨:而且,如果澈哥结婚,就会失去一切 + +△云想脸色苍白 + +云想:你的意思是,如果我和程澈在一起,他就会失去所有? +宋谨:是的 +云想:那我不能害他 +观鹤:想想,你要做什么? +云想:我要离开他 + +【程澈的坚持】 + +10-3 场 黄昏 外 学校天台 +人物:程澈、云想 + +△程澈找到准备离开的云想 + +程澈:云想,你要去哪里? +云想:程澈,我们分手吧 +程澈:为什么? +云想:因为我不能让你为了我失去一切 +程澈:云想,你听我说 +云想:不,程澈。程氏集团是你父亲的心血,你不能因为我而失去它 + +△程澈紧紧抱住云想 + +程澈:云想,没有你,我要那些财产有什么用? +云想:程澈,你要理智一点 +程澈:我很理智。我的理智告诉我,你比任何财产都重要 +云想(流泪):可是... +程澈:云想,相信我,我会找到解决办法的 + +【程威的威胁】 + +10-4 场 夜 内 程威办公室 +人物:程威、云想 + +△云想主动来找程威 + +程威:云想小姐,欢迎 +云想:程叔叔,我想和您谈谈 +程威:我知道你想说什么 +云想:请您放过程澈 +程威:这很简单,只要你离开他 +云想:如果我离开,您就不会夺走程氏集团? +程威:当然,我这样做,也是为了澈儿好 + +△程威拿出一张支票 + +程威:这是五千万,够你下半辈子花了 +云想:我不要钱 +程威:那你要什么? +云想:我要程澈幸福 +程威:那就离开他 + +【真相大白】 + +10-5 场 夜 内 程澈房间 +人物:程澈、宋谨、私家侦探 + +△私家侦探带来了调查结果 + +侦探:程少爷,我查到了真相 +程澈:说 +侦探:那份遗嘱是假的 +程澈:什么? +侦探:您父亲的真正遗嘱在这里 + +△侦探拿出真正的遗嘱 + +侦探:上面写着,无论您是否结婚,都拥有完全的继承权 +宋谨:那程威为什么要这样做? +侦探:因为他欠了巨额赌债,需要钱 + +△程澈愤怒地握紧拳头 + +程澈:他居然敢欺骗我! +宋谨:澈哥,现在怎么办? +程澈:明天的董事会,我要揭穿他的真面目 + +【第10集结尾钩子】 + +10-6 场 深夜 外 机场 +人物:云想、程威的手下 + +△云想拖着行李箱准备离开 +△程威的手下出现 + +手下:云想小姐,程威先生有话要转达 +云想:什么话? +手下:如果你不离开,程澈就会出事 +云想:你们想做什么? +手下:程威先生说,明天的董事会,程澈可能会遇到意外 + +△云想脸色大变 + +云想:我知道了 + +△云想拿出手机,给程澈发了最后一条短信 +△短信内容:"程澈,对不起,我必须离开。请你保重。" + +【第10集完】 + +==== 第11集:绝地反击,爱情胜利 ==== + +【董事会摊牌】 + +11-1 场 日 内 程氏集团董事会 +人物:程澈、程威、程枭、董事们、律师 + +△程澈带着律师和证据出现在董事会 + +程澈:各位董事,今天我要揭露一个真相 +程威:澈儿,你要做什么? +程澈:我要揭露你的谎言 + +△程澈拿出真正的遗嘱 + +程澈:这是我父亲真正的遗嘱 +程威(慌张):不可能! +律师:经过专业鉴定,这份遗嘱是真实有效的 +程澈:上面明确写着,我拥有程氏集团的完全继承权 + +△董事们议论纷纷 + +董事A:那之前的遗嘱是假的? +程澈:是的,而且我还查到了程威伪造遗嘱的证据 + +△程澈播放录音,是程威和伪造者的对话 + +程威(录音):一定要做得逼真一点,不能让澈儿发现 + +△全场震惊 + +程枭:程威,你怎么能这样做? +程威:我...我是为了澈儿好 +程澈:为了我好?你是为了还赌债! + +【程威的末路】 + +11-2 场 日 内 程氏集团董事会(续) + +△程澈继续揭露程威的罪行 + +程澈:程威不仅伪造遗嘱,还威胁我的女朋友 +程威:我没有! +程澈:宋谨,把录音放出来 + +△播放程威威胁云想的录音 + +程威(录音):如果你不离开程澈,他就会出事 + +△董事们愤怒了 + +董事B:程威,你太过分了! +董事C:这种人不配留在程氏集团! +程枭:程威,你让我太失望了 + +△程威知道大势已去 + +程威:好,我承认,我做了这些事 +程澈:为什么? +程威:因为我嫉妒你!嫉妒你拥有一切! +程澈:二叔,你本来也可以拥有这些 +程威:但是你父亲只信任你! + +△保安进来带走程威 + +程威(被带走时):程澈,你会后悔的! + +【寻找云想】 + +11-3 场 日 外 机场 +人物:程澈、宋谨、观鹤 + +△程澈疯狂寻找云想 + +程澈:她的航班是几点? +宋谨:下午三点,飞往巴黎 +观鹤:现在已经两点半了 +程澈:来得及! + +△程澈狂奔向登机口 +△但是被安检拦住 + +安检:先生,您没有机票不能进去 +程澈:求求你,让我进去找我的女朋友 +安检:抱歉,这是规定 + +△程澈绝望地看着登机口 + +【云想的回心转意】 + +11-4 场 日 内 飞机上 +人物:云想、空姐、乘客 + +△云想坐在飞机上,眼中含泪 +△飞机准备起飞 +△突然,她听到机场广播 + +广播:云想小姐,云想小姐,程澈在机场等您,请您下飞机 + +△云想震惊地站起来 + +空姐:小姐,请坐好,飞机要起飞了 +云想:不,我要下去 +空姐:抱歉,飞机已经关舱门了 + +△云想看向窗外,看到程澈在跑道上 +△程澈举着一个大牌子:"云想,我爱你!" + +云想(大喊):停飞机!我要下去! + +△其他乘客被感动 + +乘客A:让她下去吧! +乘客B:这是真爱啊! + +△机长最终同意让云想下飞机 + +【机场重逢】 + +11-5 场 日 外 机场跑道 +人物:程澈、云想、机场工作人员 + +△云想从飞机上下来 +△程澈冲向她 + +程澈:云想! +云想:程澈! + +△两人紧紧拥抱 + +云想:你怎么进来的? +程澈:我买了机票,然后又退了 +云想(笑着哭):你个傻瓜 +程澈:云想,程威的事情已经解决了 +云想:真的吗? +程澈:真的,我们再也不用分开了 + +△程澈单膝跪下,拿出戒指 + +程澈:云想,嫁给我吧 +云想:程澈... +程澈:我向你保证,从今以后,没有任何人能够分开我们 +云想(点头):我愿意! + +△周围的人都在鼓掌 +△两人深情拥吻 + +【第11集结尾钩子】 + +11-6 场 夜 内 程澈房间 +人物:程澈、云想 + +△两人相拥而眠 +△程澈的手机响起 +△是一条新闻推送:"程氏集团少爷机场求婚成功,网友直呼太浪漫" + +△程澈看着新闻,微笑 + +程澈(OS):云想,我们的故事才刚刚开始 + +【第11集完】 + +==== 第12集:幸福结局,爱情永恒 ==== + +【婚礼筹备】 + +12-1 场 日 内 婚纱店 +人物:云想、观鹤、程澈、宋谨 + +△云想在试婚纱 +△观鹤在旁边帮忙 + +观鹤:想想,你穿这件太美了! +云想:真的吗? +程澈(痴迷地看着):美得像天使 +宋谨:澈哥,你的口水要流出来了 + +△大家都笑了 + +云想:程澈,你觉得这件怎么样? +程澈:只要是你穿的,都是最美的 +观鹤:澈哥,你这个回答太标准了 +程澈:因为这是我的真心话 + +【家人祝福】 + +12-2 场 日 内 程家客厅 +人物:程澈、云想、程枭、云想父母 + +△两家人聚在一起讨论婚礼 + +程枭:云想,欢迎你成为我们程家的一员 +云想:谢谢爷爷 +云想妈妈:澈儿,想想就交给你了 +程澈:阿姨,我会用生命保护她的 +云想爸爸:澈儿,我们相信你 + +△程枭拿出一个盒子 + +程枭:这是程家的传家宝,现在传给你们 +云想:爷爷,这太贵重了 +程枭:你是程家的媳妇,这是你应得的 + +【婚礼现场】 + +12-3 场 日 外 教堂 +人物:程澈、云想、所有亲友 + +△豪华的婚礼现场 +△程澈穿着白色西装,帅气逼人 +△云想穿着白色婚纱,美若天仙 + +牧师:程澈先生,你愿意娶云想小姐为妻吗? +程澈:我愿意 +牧师:云想小姐,你愿意嫁给程澈先生为妻吗? +云想:我愿意 + +△两人交换戒指 + +牧师:现在,你们可以亲吻了 + +△程澈掀起云想的头纱,深情凝视 + +程澈:云想,我爱你 +云想:我也爱你,程澈 + +△两人深情拥吻 +△全场掌声雷动 + +【幸福时光】 + +12-4 场 日 外 海边别墅 +人物:程澈、云想 + +△蜜月旅行,两人在海边别墅 +△云想在沙滩上奔跑 +△程澈在后面追 + +程澈:云想,等等我! +云想:追不到我! + +△程澈追上云想,两人一起倒在沙滩上 + +云想:程澈,你说我们会一直这么幸福吗? +程澈:会的,我保证 +云想:如果有一天你不爱我了怎么办? +程澈:那就是世界末日了 + +△云想笑着打程澈 + +云想:你就会说好听的 +程澈:因为你值得世界上最好听的话 + +【一年后】 + +12-5 场 日 内 医院 +人物:程澈、云想、医生 + +△云想在做产检 +△程澈紧张地陪在身边 + +医生:恭喜你们,是个健康的男孩 +程澈(激动):真的吗? +医生:是的,预产期是下个月 +云想:程澈,我们要当爸爸妈妈了 +程澈:云想,谢谢你给我一个完整的家 + +△程澈轻抚云想的肚子 + +程澈:宝宝,爸爸爱你 +云想:他在踢我,好像在回应你 +程澈:他一定是个聪明的孩子 +云想:像你一样聪明,像我一样善良 + +【完美结局】 + +12-6 场 日 外 程家花园 +人物:程澈、云想、宝宝、程枭、双方父母、观鹤、宋谨 + +△三年后,程家花园里举办宝宝的生日派对 +△小程澈(宝宝)在草地上玩耍 + +小程澈:爸爸,抱抱! +程澈:来,爸爸抱 + +△程澈抱起儿子 +△云想在旁边微笑 + +云想:程澈,你还记得我们第一次见面吗? +程澈:当然记得,你撞了我的车 +云想:那时候我怎么也想不到,会和你结婚生子 +程澈:这就是命运 + +△观鹤走过来 + +观鹤:想想,你们太幸福了,我都嫉妒了 +云想:观鹤,你的幸福也会来的 +宋谨:是啊,我已经给观鹤介绍了好几个男朋友了 +观鹤:宋谨! + +△大家都笑了 + +程枭:澈儿,云想,看到你们这么幸福,我就放心了 +程澈:爷爷,这都是您的功劳 +程枭:不,这是你们自己争取来的 + +△夕阳西下,一家人其乐融融 + +云想(OS):有时候我会想,如果当初没有撞到程澈的车,我们还会相遇吗? +程澈(OS):不管怎样,我们都会相遇的。因为你是我命中注定的人 + +△镜头拉远,温馨的画面定格 + +【字幕】:爱情不是偶然,而是必然。当两个相爱的人走到一起,全世界都会为他们让路。 + +【全剧终】 + +==== 创作说明 ==== + +【第10-12集改编亮点】 +1. **终极反转**:程威身份揭秘,增加戏剧张力 +2. **机场追爱**:经典浪漫桥段,满足观众期待 +3. **完美结局**:婚礼、生子、家庭和睦的圆满收官 +4. **情感升华**:从恋爱到婚姻到家庭的完整弧线 +5. **商业闭环**:所有矛盾解决,给观众满足感 + +【情绪设计】 +1. **紧张刺激**:董事会对决、机场追逐 +2. **浪漫甜蜜**:求婚、婚礼、蜜月 +3. **温馨感人**:家庭和睦、生儿育女 +4. **圆满结局**:所有角色都有好的归宿 + +【商业价值】 +1. **话题性**:机场求婚、豪华婚礼等热门话题 +2. **情绪满足**:完美结局给观众最大的情绪满足 +3. **二创素材**:婚礼、求婚等场景适合短视频传播 +4. **IP延展**:为可能的续集或衍生剧留下空间 + +【与原著对比】 +- 大幅压缩时间线,快速推进到结局 +- 增加家族斗争元素,提升戏剧性 +- 强化浪漫元素,满足观众期待 +- 完善所有角色的结局,增加完整性 + +【整体总结】 +《好想你知道》改编版成功将原著的温馨校园恋爱故事,魔改为节奏紧凑、情节密集、爽点频出的霸总宠妻短剧。通过人设极致化、情节戏剧化、节奏快速化的改编策略,打造出具有强烈网感和商业价值的爆款短剧。 \ No newline at end of file diff --git a/doc/参考/第4-6集剧本.txt b/doc/参考/第4-6集剧本.txt new file mode 100644 index 0000000..d3e23a8 --- /dev/null +++ b/doc/参考/第4-6集剧本.txt @@ -0,0 +1,452 @@ +【第4-6集剧本 - 关系升温,外部冲突】 + +==== 第4集:确立关系,身份曝光 ==== + +【开场回应表白】 + +4-1 场 晨 外 学校门口 +人物:云想、程澈、围观学生 + +△云想在学校门口等程澈 +△程澈骑摩托车出现,看到云想眼睛一亮 + +程澈(下车):等很久了? +云想(脸红):没有...程澈,关于昨天你说的话... +程澈(紧张):嗯? +云想(鼓起勇气):我...我愿意 + +△程澈愣住,随即露出从未有过的温柔笑容 + +程澈:真的? +云想(点头):真的 + +△程澈激动地将云想拉入怀中 +△围观学生纷纷拍照,议论纷纷 + +学生甲:天哪!程澈居然笑了! +学生乙:他们在一起了! +学生丙:这是什么神仙爱情! + +程澈(对云想):从今天开始,你就是我的女朋友了 +云想(害羞):嗯... +程澈:我会让全世界都知道,你是我程澈的女人 + +【宠妻模式全面升级】 + +4-2 场 日 内 教室 +人物:程澈、云想、全班同学、班主任 + +△上课时间,程澈突然站起来 + +程澈:老师,我有话要说 +班主任:程澈,现在是上课时间... +程澈:很重要的事 + +△程澈走到云想身边,当众牵起她的手 + +程澈(对全班):我正式宣布,云想是我的女朋友。以后谁敢欺负她,就是跟我程澈过不去 + +△全班哗然,云想脸红得像苹果 +△班主任也震惊得说不出话 + +程澈(继续):另外,从今天开始,云想的一切费用我来承担。她不需要任何人的同情和施舍 + +△程澈拿出一张黑卡,放在云想桌上 + +程澈:这张卡没有限额,想买什么就买什么 +云想(推辞):程澈,这太贵重了... +程澈(霸道):我的女人,就应该被宠着 + +【林雅反击 - 外部冲突升级】 + +4-3 场 日 外 学校天台 +人物:林雅、云想、林雅的跟班 + +△云想独自在天台吃饭 +△林雅带着几个跟班出现 + +林雅:云想,我们该好好谈谈了 +云想(警惕):林雅,你想干什么? +林雅:我想让你认清现实 + +△林雅拿出一叠照片,扔在云想面前 +△照片内容:云想在孤儿院的生活照片 + +林雅:看看你的出身,再看看程澈的身份。你觉得你们合适吗? +云想(愤怒):出身不能决定一切! +林雅(冷笑):是吗?那你知道程澈的真实身份吗? + +△林雅拿出平板,播放一段视频 +△视频内容:程澈在商业会议上的画面,被称为"程少爷" + +林雅:程氏集团未来的继承人,身价百亿。而你,一个孤儿院出来的野丫头 +云想(咬牙):程澈不在乎这些 +林雅:他现在不在乎,不代表以后不在乎。等他玩腻了,你觉得他还会要你吗? + +△云想被说中痛处,眼中含泪 + +林雅(得意):识相的话,主动离开他。否则,我有一万种方法让你在这个学校待不下去 + +【程澈护妻 - 霸道宣言】 + +4-4 场 日 外 学校天台(接上场) +人物:程澈、云想、林雅、林雅跟班 + +△程澈突然出现,脸色阴沉 + +程澈:林雅,你在干什么? +林雅(撒娇):澈哥哥,我只是在跟妹妹聊天 +程澈(看向云想):她说了什么? + +△云想摇头,不想惹麻烦 +△程澈看到地上的照片,脸色更加难看 + +程澈(冷声):这些照片哪来的? +林雅:我只是想让她认清现实... +程澈(打断):认清什么现实? + +△程澈走到云想身边,将她拉入怀中 + +程澈(对林雅):我最后警告你一次,不许再骚扰我的女人 +林雅:澈哥哥,我们从小一起长大,你为了一个外人... +程澈(冷笑):外人?她是我选择的人,是我要用一生去保护的人 + +△程澈转身对云想 + +程澈:云想,不管别人怎么说,你都要记住,在我心里,你比任何人都重要 +云想(感动):程澈... +程澈:我不在乎你的出身,我只在乎你这个人 + +△程澈当众吻了云想的额头 +△林雅气得脸色发白,带着跟班离开 + +【第4集结尾钩子】 + +4-5 场 夜 内 程澈房间 +人物:程澈、程枭(电话) + +△程澈接到父亲的电话 + +程枭(电话):小澈,听说你在学校公开了和云想的关系? +程澈:是的 +程枭:你知道这意味着什么吗? +程澈:什么意思? +程枭:林家那边已经知道了,他们很不高兴 +程澈:我不在乎 +程枭:但是我在乎!你忘了我们和林家的合作了吗? +程澈:爸,我不会为了商业利益牺牲我的感情 +程枭:程澈,你还年轻,不懂事。这件事到此为止 +程澈:如果您要我在云想和家族利益之间选择,我选择云想 + +△程澈挂断电话,表情坚决 + +程澈(OS):不管付出什么代价,我都不会放弃云想 + +【第4集完】 + +==== 第5集:家族压力,感情考验 ==== + +【家族施压】 + +5-1 场 日 内 程氏集团董事长办公室 +人物:程枭、林董事长、程澈 + +△程澈被叫到父亲的办公室 +△林董事长也在场,脸色不善 + +程枭:小澈,林叔叔有话要跟你说 +林董事长:程澈,你和我女儿从小就有婚约 +程澈:那是你们大人的决定,我从来没有同意过 +林董事长:现在你为了一个来路不明的女孩,要毁掉两家的合作? +程澈:云想不是来路不明,她是我选择的人 + +△林董事长拍桌而起 + +林董事长:程枭,你就是这么教育儿子的? +程枭(为难):小澈,你先回去,这件事我们再商量 +程澈:没什么好商量的。我不会娶林雅,也不会放弃云想 + +△程澈转身要走 + +林董事长:程澈,如果你坚持这样,我们林家就要重新考虑和程氏的合作了 +程澈(回头):那是您的选择 + +【云想的自我怀疑】 + +5-2 场 日 内 学校图书馆 +人物:云想、观鹤 + +△云想独自在图书馆学习,心不在焉 +△观鹤坐到她对面 + +观鹤:想想,你看起来心情不好 +云想:观鹤,你说我和程澈真的合适吗? +观鹤:为什么这么问? +云想:我们的出身差距太大了,他的家人肯定不会接受我 +观鹤:想想,真正的爱情不应该被出身束缚 +云想:可是现实很残酷... +观鹤:如果你真的爱他,就应该相信他的选择 + +△云想陷入沉思 + +观鹤:想想,不管你做什么决定,我都会支持你 +云想:谢谢你,观鹤 + +【程澈的坚持】 + +5-3 场 黄昏 外 学校操场 +人物:程澈、云想 + +△程澈找到云想,发现她在哭 + +程澈(心疼):怎么了?谁欺负你了? +云想:程澈,我们分手吧 + +△程澈震惊 + +程澈:为什么? +云想:我们不合适,你的家人不会接受我的 +程澈:我不在乎他们的想法 +云想:但是我在乎!我不想成为你的负担 + +△程澈紧紧抱住云想 + +程澈:云想,听我说。不管发生什么,我都不会放弃你 +云想:可是... +程澈:没有可是。我程澈说过的话,从来不会反悔 + +△程澈捧起云想的脸 + +程澈:相信我,好吗? +云想(哭着点头):嗯... + +【危机升级 - 绑架事件】 + +5-4 场 夜 外 回家路上 +人物:云想、神秘人、程澈 + +△云想独自走在回家的路上 +△突然被几个黑衣人包围 + +黑衣人甲:云想小姐,跟我们走一趟 +云想(害怕):你们是谁? +黑衣人乙:有人想见你 + +△云想想要逃跑,被抓住 +△正在此时,程澈的摩托车声响起 + +程澈(冷声):放开她 +黑衣人甲:程少爷,我们只是奉命行事 +程澈:奉谁的命? + +△一辆黑色轿车停下,林董事长走出来 + +林董事长:是我的命 +程澈(愤怒):林叔叔,您这是什么意思? +林董事长:我要让这个女孩知道,她配不上你 + +△程澈挡在云想面前 + +程澈:想动她,先过我这关 +林董事长:程澈,你要为了一个女孩跟我翻脸? +程澈:如果您要伤害她,那就是 + +【第5集结尾钩子】 + +5-5 场 夜 外 回家路上(接上场) + +△对峙中,程澈的手机响起 +△来电显示:爸爸 + +程澈(接电话):什么事? +程枭(电话):小澈,立刻回来,出大事了 +程澈:什么大事? +程枭:林家撤资了,公司股价暴跌,董事会要求你立刻和林雅订婚 + +△程澈脸色大变 +△林董事长得意地笑了 + +林董事长:程澈,现在你还要坚持吗? + +△云想听到电话内容,眼中闪过痛苦 + +云想(对程澈):去吧,公司更重要 +程澈(坚决):不,你更重要 + +△程澈挂断电话,牵起云想的手 + +程澈:我们走 + +【第5集完】 + +==== 第6集:最终选择,爱情胜利 ==== + +【董事会摊牌】 + +6-1 场 日 内 程氏集团会议室 +人物:程澈、程枭、各位董事、林董事长 + +△紧急董事会召开 +△程澈被要求出席 + +董事甲:程澈,因为你的任性,公司损失惨重 +董事乙:你必须立刻和林雅订婚,挽回林家的合作 +程澈:我拒绝 + +△会议室一片哗然 + +程枭:小澈,你知道你在说什么吗? +程澈:我很清楚。我不会为了商业利益出卖我的感情 +林董事长:程澈,你要为你的选择负责 +程澈:我会负责,但不是用这种方式 + +△程澈站起来,面对所有人 + +程澈:各位叔叔,我程澈从小就被培养成程氏的继承人。但是今天,我要告诉你们,如果继承程氏意味着要放弃我爱的人,那我宁可不要 + +△全场震惊 + +程澈:从今天开始,我放弃程氏集团的继承权 +程枭:程澈! +程澈:爸,对不起。但是我不能违背自己的心 + +【云想的成长 - 主动出击】 + +6-2 场 日 内 学校教室 +人物:云想、林雅、全班同学 + +△云想主动找到林雅 + +云想:林雅,我们谈谈 +林雅(得意):有什么好谈的?程澈很快就会是我的未婚夫了 +云想:我不会让你得逞的 +林雅(冷笑):就凭你? + +△云想拿出手机,播放一段录音 +△录音内容:林雅指使人威胁云想的对话 + +云想:这段录音如果传出去,你觉得程澈会怎么看你? +林雅(慌张):你...你想干什么? +云想:我要你公开道歉,并且永远不要再骚扰我和程澈 + +△全班同学围观,议论纷纷 + +云想(大声):我云想虽然出身贫寒,但我有自己的尊严。我不会因为任何人的威胁而放弃我的爱情 + +△同学们纷纷鼓掌 + +学生甲:云想说得对! +学生乙:真正的爱情不应该被门第束缚! +学生丙:我们支持你! + +【程澈的惊喜 - 隐藏实力曝光】 + +6-3 场 日 内 程氏集团会议室 +人物:程澈、程枭、董事们、神秘助理 + +△正当董事会准备通过决议时,程澈的助理进来 + +助理:程少爷,您要的文件 +程澈:谢谢 + +△程澈拿出一叠文件 + +程澈:各位,在我放弃继承权之前,我想让你们看看这个 + +△程澈将文件分发给每个人 +△董事们看后纷纷震惊 + +董事甲:这...这是什么? +程澈:这是我这三年来秘密投资的项目清单 +董事乙:天哪,这些项目的总价值... +程澈:超过程氏集团目前的市值 + +△程枭震惊地看着儿子 + +程枭:小澈,你什么时候... +程澈:爸,您以为我这三年只是在上学吗?我一直在为接管程氏做准备 + +△程澈站起来,气场强大 + +程澈:林家的撤资确实会让程氏损失,但不会伤筋动骨。相反,我的这些项目,足以让程氏的实力翻倍 +林董事长(慌张):这不可能... +程澈:林叔叔,您可以选择继续合作,也可以选择离开。但是,请不要再威胁我的女人 + +【大团圆结局】 + +6-4 场 黄昏 外 学校天台 +人物:程澈、云想 + +△程澈找到云想,将她拉入怀中 + +程澈:听说你今天很勇敢 +云想:我不想再做被保护的小女孩了 +程澈:那你想做什么? +云想:我想做能够站在你身边的女人 + +△程澈深情地看着云想 + +程澈:云想,你知道吗?从第一眼看到你,我就知道,你就是我要找的人 +云想:为什么? +程澈:因为你让我相信,这个世界上还有纯真的美好 + +△程澈单膝跪下,拿出一枚戒指 + +程澈:云想,虽然我们还年轻,但我想让全世界都知道,你是我程澈这辈子唯一的女人。你愿意接受这枚承诺戒指吗? + +△云想感动得泪流满面 + +云想:我愿意 + +△程澈为云想戴上戒指,两人拥吻 +△夕阳西下,两人的身影被拉得很长 + +【第6集结尾 - 完美收官】 + +6-5 场 夜 内 程家客厅 +人物:程澈、云想、程枭、程澈母亲 + +△程澈带云想回家见父母 +△程枭和程澈母亲已经在客厅等候 + +程枭:想想,对不起,之前的事情是叔叔不对 +云想:程叔叔,您不用道歉 +程澈母亲:想想,欢迎你成为我们家的一员 + +△程澈母亲拿出一条项链 + +程澈母亲:这是程家传了三代的项链,现在它属于你了 +云想(感动):阿姨,这太贵重了... +程澈母亲:你是小澈选择的人,就是我们的女儿 + +△程澈握住云想的手 + +程澈:从今以后,没有人能够分开我们 +云想:嗯,我们永远在一起 + +△镜头拉远,一家人其乐融融 +△字幕出现:"真正的爱情,能够战胜一切阻碍" + +【第6集完】 + +==== 创作说明 ==== + +【第4-6集改编亮点】 +1. **关系确立**:第4集直接确立恋爱关系,节奏紧凑 +2. **冲突升级**:家族压力、商业威胁、绑架危机层层递进 +3. **人物成长**:云想从被动接受保护到主动反击 +4. **爽点密集**:程澈护妻、实力曝光、完美反击 +5. **情感升华**:从保护关系升华为平等的爱情 + +【商业化设计】 +1. **付费点**:程澈实力曝光、求婚场面、家族认可 +2. **话题性**:霸总放弃继承权、灰姑娘逆袭、真爱胜利 +3. **情绪调动**:甜虐并存,观众情绪过山车 +4. **代入感**:每个女孩都梦想被这样宠爱 + +【与原著对比】 +- 大幅压缩时间线,删除冗余情节 +- 强化程澈的霸总属性和保护欲 +- 增加商业斗争元素,提升戏剧冲突 +- 云想的成长弧线更加明显和励志 +- 结局更加圆满,满足观众期待 \ No newline at end of file diff --git a/doc/参考/第7-9集剧本.txt b/doc/参考/第7-9集剧本.txt new file mode 100644 index 0000000..537fd10 --- /dev/null +++ b/doc/参考/第7-9集剧本.txt @@ -0,0 +1,445 @@ +【第7-9集剧本 - 危机考验,感情波折】 + +==== 第7集:新的威胁,信任危机 ==== + +【神秘敌人出现】 + +7-1 场 日 外 咖啡厅 +人物:云想、神秘男子(陈总)、程澈 + +△云想独自在咖啡厅等程澈 +△一个中年男子坐到她对面 + +陈总:云想小姐,我们终于见面了 +云想(警惕):你是谁? +陈总:我姓陈,是程氏集团的竞争对手 +云想:你想干什么? +陈总:我想跟你做个交易 + +△陈总拿出一张支票 + +陈总:一千万,离开程澈 +云想(愤怒):你以为我是什么人? +陈总:每个人都有价格,只是多少的问题 +云想:我不会为了钱背叛程澈 + +△陈总收起支票,拿出一叠照片 + +陈总:那这些呢? + +△照片内容:程澈和其他女孩的亲密照片(PS的) + +陈总:程澈在你之前,可是有很多女朋友的 +云想(震惊):这些照片... +陈总:都是真的。你以为你是他的唯一吗? + +△正在此时,程澈出现 + +程澈(冷声):陈总,你在这里做什么? +陈总(起身):程少爷,只是偶遇你的女朋友,聊聊天 +程澈:以后不要再接近她 +陈总:程少爷,有些事情,瞒得了一时,瞒不了一世 + +△陈总离开,留下照片 +△程澈看到照片,脸色大变 + +程澈:云想,这些照片... +云想(冷淡):你不用解释 +程澈:这些都是假的! +云想:是吗?那为什么你看到照片会这么紧张? + +【误会加深】 + +7-2 场 日 内 学校教室 +人物:云想、宋谨、观鹤 + +△云想心不在焉地上课 +△宋谨偷偷递纸条给她 + +纸条内容:"想想,澈哥找你" + +△云想看了一眼,没有理会 +△下课后,观鹤走到云想身边 + +观鹤:想想,你和程澈吵架了? +云想:没有 +观鹤:但是你看起来很不开心 +云想:观鹤,你觉得一个人会为了另一个人改变吗? +观鹤:如果是真爱的话,会的 +云想:那如果这个人以前有很多女朋友呢? +观鹤:过去不重要,重要的是现在 + +△云想陷入沉思 + +【程澈的解释】 + +7-3 场 黄昏 外 学校天台 +人物:程澈、云想 + +△程澈终于找到云想 + +程澈:云想,我们需要谈谈 +云想:没什么好谈的 +程澈:关于那些照片,我可以解释 +云想:你不用解释,我理解 +程澈:你理解什么? +云想:你是程氏集团的少爷,身边有很多女孩很正常 + +△程澈急了 + +程澈:云想,你听我说,那些照片都是假的! +云想:假的?那为什么做得这么逼真? +程澈:因为有人想要破坏我们的关系 +云想:程澈,你觉得我很好骗吗? + +△云想转身要走,程澈拉住她 + +程澈:云想,相信我,好吗? +云想:程澈,我累了。我们冷静一下吧 + +△云想挣脱程澈的手,离开 +△程澈一个人站在天台上,表情痛苦 + +【第7集结尾钩子】 + +7-4 场 夜 内 程澈房间 +人物:程澈、宋谨(电话) + +△程澈独自坐在房间里,看着云想的照片 +△手机响起,是宋谨的电话 + +宋谨(电话):澈哥,我查到了那些照片的来源 +程澈:说 +宋谨:是陈氏集团的人做的,他们想要搞垮你 +程澈:我知道了 +宋谨:澈哥,你打算怎么办? +程澈:我要让他们付出代价 + +△程澈眼中闪过危险的光芒 + +程澈:敢动我的女人,他们死定了 + +【第7集完】 + +==== 第8集:危机升级,感情破裂 ==== + +【陈总的阴谋】 + +8-1 场 日 内 陈氏集团办公室 +人物:陈总、助理、林雅 + +△陈总在办公室里得意地看着监控画面 +△画面中是程澈和云想冷战的场景 + +陈总:很好,他们开始互相怀疑了 +助理:陈总,下一步怎么办? +陈总:继续加码 + +△林雅走进办公室 + +林雅:陈叔叔,您找我? +陈总:雅雅,是时候执行第二阶段计划了 +林雅:什么计划? +陈总:让程澈彻底失去云想 + +△陈总拿出一瓶药 + +陈总:这是迷药,你想办法让云想喝下去 +林雅:然后呢? +陈总:然后让程澈看到你们在一起的画面 +林雅(犹豫):这样不太好吧... +陈总:你想要程澈,就必须付出代价 + +【云想中计】 + +8-2 场 日 内 学校咖啡厅 +人物:云想、林雅 + +△云想独自在咖啡厅喝咖啡 +△林雅主动坐到她对面 + +林雅:想想,我们谈谈吧 +云想:我们没什么好谈的 +林雅:关于程澈的事情 +云想:什么? +林雅:我知道你们吵架了 +云想:这不关你的事 +林雅:想想,其实我们可以做朋友的 + +△林雅推了一杯咖啡给云想 + +林雅:这是我的道歉,之前的事情是我不对 +云想(意外):你... +林雅:我想通了,如果程澈真的爱你,我也不应该强求 + +△云想被感动,喝了咖啡 +△几分钟后,云想开始感到头晕 + +云想:我...我怎么了? +林雅(假装关心):想想,你没事吧?我送你去休息 + +【程澈误会】 + +8-3 场 日 内 学校休息室 +人物:云想(昏迷)、林雅、程澈 + +△林雅将昏迷的云想带到休息室 +△然后发短信给程澈:"快来休息室,云想出事了" + +△程澈匆忙赶到,看到林雅在照顾云想 + +程澈:她怎么了? +林雅:不知道,突然就晕倒了 +程澈(担心):有没有叫医生? +林雅:已经叫了 + +△程澈想要抱起云想 +△云想在迷药作用下,迷迷糊糊地推开程澈 + +云想(迷糊):不要...不要碰我... +程澈(震惊):云想? +云想(迷糊):我不想看到你... + +△程澈心如刀割 +△林雅在旁边假装安慰 + +林雅:程澈,也许她真的需要时间冷静 +程澈:不,她不是这样的人 +林雅:人在生气的时候,会说很多伤人的话 + +【真相部分揭露】 + +8-4 场 日 内 医务室 +人物:云想、校医、程澈、宋谨 + +△云想被送到医务室 +△校医检查后,脸色严肃 + +校医:这个学生被下了迷药 +程澈(愤怒):什么? +校医:血液中有迷药成分,幸好剂量不大 +宋谨:谁会给想想下药? + +△程澈想起林雅的异常表现 + +程澈:林雅! + +△程澈冲出医务室,去找林雅 +△但林雅已经离开学校 + +【云想的决定】 + +8-5 场 夜 内 云想房间 +人物:云想、程澈 + +△云想醒来后,程澈守在她身边 + +程澈:你醒了?感觉怎么样? +云想:我...发生了什么? +程澈:你被人下了迷药 +云想(震惊):什么? +程澈:是林雅做的 +云想:为什么? +程澈:因为有人想要破坏我们的关系 + +△云想沉默了很久 + +云想:程澈,我想我们应该分开一段时间 +程澈:为什么?现在真相已经清楚了 +云想:正是因为真相清楚了,我才更害怕 +程澈:害怕什么? +云想:害怕因为我,你会遇到更多的危险 + +△程澈紧紧抱住云想 + +程澈:云想,不要离开我 +云想(流泪):程澈,我爱你,正是因为爱你,我才不能害你 + +【第8集结尾钩子】 + +8-6 场 夜 外 云想家楼下 +人物:云想、神秘电话 + +△云想独自站在楼下 +△手机响起,是陌生号码 + +神秘声音:云想,考虑得怎么样? +云想:你是谁? +神秘声音:一个想要保护程澈的人 +云想:什么意思? +神秘声音:只要你离开他,他就会安全 +云想:如果我不离开呢? +神秘声音:那他就会有生命危险 + +△电话挂断,云想脸色苍白 + +云想(OS):为了保护程澈,我必须离开他 + +【第8集完】 + +==== 第9集:生死考验,真爱觉醒 ==== + +【云想的牺牲】 + +9-1 场 晨 内 云想房间 +人物:云想 + +△云想收拾行李,准备离开 +△拿起程澈送的戒指,眼中含泪 + +云想(OS):程澈,对不起。我这样做,都是为了保护你 + +△云想写了一封信,放在桌上 +△信的内容:"程澈,我们不合适,请忘记我。- 云想" + +【程澈的发现】 + +9-2 场 日 内 程澈房间 +人物:程澈、宋谨 + +△程澈发现云想不见了 +△冲到她的房间,看到信件 + +程澈(愤怒):不可能!她不会这样做! +宋谨:澈哥,也许她真的... +程澈:不!一定有人威胁了她! + +△程澈拿出手机,疯狂拨打云想的号码 +△但云想的手机已经关机 + +程澈:宋谨,动用所有关系,一定要找到她! +宋谨:是,澈哥! + +【陈总的最后一击】 + +9-3 场 日 内 废弃仓库 +人物:云想、陈总、手下 + +△云想被带到一个废弃仓库 +△陈总出现在她面前 + +陈总:云想小姐,欢迎来到我的地盘 +云想:你想要什么? +陈总:很简单,给程澈打个电话,告诉他你不爱他了 +云想:我不会的 +陈总:那就别怪我不客气了 + +△陈总的手下逼近云想 +△云想害怕地后退 + +陈总:程澈为了你,已经得罪了很多人。现在,是时候让他付出代价了 +云想:你们想对程澈做什么? +陈总:如果你不配合,他就会出车祸 + +△陈总拿出手机,播放程澈开车的实时画面 + +陈总:我的人已经在路上等他了 +云想(恐惧):不要伤害他! +陈总:那就配合我 + +【程澈的营救】 + +9-4 场 日 外 废弃仓库外 +人物:程澈、宋谨、保镖 + +△程澈通过GPS定位找到了云想 +△带着保镖包围了仓库 + +程澈(对讲机):所有人注意,确保云想的安全 +宋谨:澈哥,陈总的人很多 +程澈:我不在乎。今天,我一定要救出云想 + +△程澈冲进仓库 + +【最终对决】 + +9-5 场 日 内 废弃仓库 +人物:程澈、云想、陈总、双方手下 + +△程澈出现在仓库里 + +程澈:放开她! +陈总:程澈,你终于来了 +程澈:你想要什么? +陈总:我要你跪下,求我放过她 + +△程澈毫不犹豫地跪下 + +程澈:我求你,放过她 +云想(震惊):程澈,不要! +陈总(得意):堂堂程氏集团的少爷,居然为了一个女人下跪 +程澈:只要你放过她,我什么都愿意做 + +△云想被感动得泪流满面 + +云想:程澈,你为什么要这样做? +程澈:因为我爱你,胜过我的生命 + +△正在此时,警察包围了仓库 +△原来程澈早就报了警 + +陈总(慌张):不可能! +程澈(站起来):陈总,游戏结束了 + +【真爱告白】 + +9-6 场 黄昏 外 医院 +人物:程澈、云想 + +△云想在医院接受检查 +△程澈守在她身边 + +云想:程澈,对不起,我不应该不相信你 +程澈:是我不好,没有保护好你 +云想:程澈,你为什么愿意为我做这么多? +程澈:因为你是我的全世界 + +△程澈握住云想的手 + +程澈:云想,经过这次的事情,我更加确定,我这辈子只爱你一个人 +云想:我也是,程澈。我永远不会再离开你 + +△两人深情拥吻 + +【第9集结尾钩子】 + +9-7 场 夜 内 程澈房间 +人物:程澈、云想 + +△两人相拥而眠 +△程澈的手机响起,是一条短信 +△短信内容:"程澈,这只是开始。- 神秘人" + +△程澈看到短信,眉头紧皱 +△但他没有吵醒云想,而是将她抱得更紧 + +程澈(OS):不管还有什么威胁,我都会保护好云想 + +【第9集完】 + +==== 创作说明 ==== + +【第7-9集改编亮点】 +1. **危机升级**:从情感误会到生命威胁,层层递进 +2. **人物考验**:通过危机考验两人的真爱 +3. **反派立体化**:陈总和林雅的阴谋更加复杂 +4. **情感深化**:通过分离和重聚,感情更加深厚 +5. **动作戏份**:增加营救戏码,提升观赏性 + +【情绪设计】 +1. **虐心情节**:误会、分离、威胁制造情绪波动 +2. **甜蜜反转**:危机后的重聚更加珍贵 +3. **英雄救美**:程澈为爱下跪,展现真爱力量 +4. **成长弧线**:云想学会为爱勇敢,程澈学会为爱牺牲 + +【商业价值】 +1. **话题性**:霸总为爱下跪、生死营救等话题 +2. **情绪商品**:虐恋情深,观众情绪投入度高 +3. **付费点**:营救高潮、真爱告白等关键情节 +4. **完播率**:每集结尾的悬念设置 + +【与原著对比】 +- 大幅增加动作戏和悬疑元素 +- 强化反派威胁,提升戏剧张力 +- 压缩时间线,删除冗余支线 +- 情感线更加极致化和戏剧化 \ No newline at end of file diff --git a/doc/参考/诊断与资产评估.txt b/doc/参考/诊断与资产评估.txt new file mode 100644 index 0000000..2d4368c --- /dev/null +++ b/doc/参考/诊断与资产评估.txt @@ -0,0 +1,75 @@ +【诊断与资产评估报告】 + +==== 故事内核诊断 ==== + +核心故事线:校园青春恋爱 + 成长治愈 +- 失去父亲的孤独少女云想 VS 外冷内热的学霸程澈 +- 从互相看不顺眼到暗生情愫的经典"欢喜冤家"模式 +- 治愈系成长:程澈的出现如"一束光"照亮云想的黑暗世界 + +情感内核强度:★★★☆☆ +- 有一定的情感基础,但缺乏足够的戏剧张力 +- 节奏偏慢,爽点密度不足 + +==== 可继承的宝贵资产 ==== + +【高光情节】 +1. 程澈为云想打架护短(第6-7集)- 经典"护妻打脸"素材 +2. 咖啡店"上帝"调戏桥段(第20集)- 甜宠互动,网感十足 +3. 音乐会深情献唱(第25集)- 公开示爱,情感高潮 +4. 程澈霸道赶走搭讪男(第21集)- 占有欲爆棚,观众爽点 + +【神来之笔对白】 +- "她是我的人,想欺负她,先看看自己几斤几两!" +- "你是不是舍不得我?" "没有。" "真的?" +- "上帝,对不起,请原谅我!"(当众羞辱反转) + +【独特人设闪光点】 +- 程澈:外冷内热学霸 + 隐藏宠妻属性 + 毒舌傲娇 +- 云想:治愈系少女 + 天然呆萌 + 坚强独立 + +==== 核心问题诊断 ==== + +【致命伤】 +1. 节奏拖沓:27集才到暧昧期,短剧黄金法则是3集定生死 +2. 爽点稀薄:缺乏密集的"打脸""逆袭""宠溺"等核心爽点 +3. 冲突不够:程澈家庭接纳云想过于顺利,缺乏戏剧张力 +4. 人设模糊:两人都太"正常",缺乏极致化标签 + +【次要问题】 +1. 配角功能性不强:宋谨、观鹤等缺乏明确的推动剧情作用 +2. 情感递进过于平缓:缺乏情绪过山车体验 +3. 网络梗语不足:对话偏文艺,缺乏当下网感 + +==== 短剧改编潜力评估 ==== + +商业价值:★★★★☆ +- 校园恋爱+治愈系是短剧热门赛道 +- 男女主人设有改造空间,可塑性强 +- 核心情感线清晰,适合短剧快节奏 + +改编难度:★★★☆☆ +- 需要大幅压缩节奏,前置爽点 +- 人设需要极致化改造 +- 冲突线需要重新设计 + +==== 初步改编建议 ==== + +【核心策略】 +将温吞校园恋爱魔改为"战神学霸归来,护妻打脸"的极致爽文模式 + +【关键改造点】 +1. 人设极致化:程澈→隐藏身份的天才学霸+宠妻狂魔;云想→被欺凌的灰姑娘+逆袭女王 +2. 冲突前置:开篇即安排云想被校园霸凌,程澈强势护短 +3. 爽点密集化:每集至少2个打脸/宠溺/逆袭爽点 +4. 节奏压缩:27集压缩至12-15集,3集内确立CP关系 + +【预期效果】 +完播率提升40%,付费转化率提升60% + +==== 结论 ==== + +这是一个具有良好改编基础的校园恋爱故事,核心情感线和人物关系清晰,但需要进行"爽文化"改造以适应短剧市场。通过节奏压缩、人设极致化、冲突强化等手段,有望打造成爆款短剧。 + +改编信心指数:85% +预期市场表现:A级(头部20%) \ No newline at end of file diff --git a/doc/参考/重大事件时间线.txt b/doc/参考/重大事件时间线.txt new file mode 100644 index 0000000..8e49e7b --- /dev/null +++ b/doc/参考/重大事件时间线.txt @@ -0,0 +1,235 @@ +【重大事件时间线.txt - 剧本圣经】 + +==== 时间线总览 ==== + +【故事时间跨度】:高三下学期(约4个月) +【叙事节奏】:快节奏,密集事件推进 +【关键时间节点】:12个重大事件,对应12集内容 + +==== 详细时间线 ==== + +【第1周 - 命运相遇】 + +**Day 1 - 第1集:霸气出场** +- 上午:云想被校园恶霸在食堂羞辱 +- 中午:程澈霸气出场,一打三护短 +- 下午:程澈接到神秘电话,身份暗示 +- 晚上:程澈对云想说"以后跟着我" + +关键转折点:两人命运交汇,保护关系建立 +情感温度:从0°升至30° + +**Day 2-3 - 第2集:宠妻日常** +- Day 2上午:程澈为云想准备爱心早餐 +- Day 2下午:程澈为云想出头对抗老师 +- Day 2晚上:程澈送云想回家 +- Day 3:观鹤温柔出场,成为潜在情敌 + +关键转折点:宠妻模式开启,情敌出现 +情感温度:从30°升至50° + +**Day 4-5 - 第3集:吃醋宣示** +- Day 4:观鹤邀请云想参加音乐社 +- Day 4下午:程澈吃醋,霸道阻止 +- Day 4晚上:程澈当众宣示主权 +- Day 5:程澈展现天才实力,神秘人调查 + +关键转折点:占有欲爆发,身份线推进 +情感温度:从50°升至70° + +--- + +【第2周 - 身份震撼】 + +**Day 6-7 - 第4集:天才曝光** +- Day 6:程澈国际奥数冠军身份曝光 +- Day 6下午:全校震惊,云想自卑 +- Day 7:云想开始逃避程澈 +- Day 7晚上:程澈开启追妻模式 + +关键转折点:身份差距显现,感情危机 +情感温度:从70°降至40° + +**Day 8-10 - 第5集:确立关系** +- Day 8:云想主动为程澈准备惊喜 +- Day 9:两人正式确立恋爱关系 +- Day 10:甜蜜日常,程澈为云想庆生 +- Day 10晚上:林雅(未婚妻)出现预告 + +关键转折点:正式成为情侣,新威胁来临 +情感温度:从40°飙升至90° + +--- + +【第3周 - 情敌考验】 + +**Day 11-12 - 第6集:情敌来袭** +- Day 11:林雅强势登场,威胁云想 +- Day 11下午:云想受打击,选择离开 +- Day 12:程澈愤怒反击,拒绝未婚妻 +- Day 12晚上:程澈坚定选择云想 + +关键转折点:面临情敌威胁,程澈做出选择 +情感温度:从90°降至60°,再升至85° + +**Day 13-14 - 第7集:家族压力** +- Day 13:程澈父亲施压,要求分手 +- Day 13下午:程澈拒绝,宁可断绝关系 +- Day 14:云想觉醒,决定为爱而战 +- Day 14晚上:两人更加珍惜彼此 + +关键转折点:家族对抗,云想成长觉醒 +情感温度:从85°降至50°,再升至80° + +--- + +【第4周 - 华丽逆袭】 + +**Day 15-16 - 第8集:天赋觉醒** +- Day 15:学校音乐比赛报名 +- Day 16:云想音乐天赋爆发,一鸣惊人 +- Day 16下午:全校刮目相看 +- Day 16晚上:程澈为云想骄傲庆祝 + +关键转折点:云想华丽逆袭,证明自己 +情感温度:从80°升至95° + +--- + +【第6周 - 生死考验】 + +**Day 17-18 - 第9集:最大危机** +- Day 17:程澈完整身份曝光(企业继承人+天才黑客) +- Day 17下午:商业对手绑架云想 +- Day 18:程澈动用所有资源营救 +- Day 18晚上:成功救出云想,消除威胁 + +关键转折点:生死考验,感情升华 +情感温度:从95°降至20°,再飙升至100° + +--- + +【第8周 - 公开宣示】 + +**Day 19-20 - 第10集:公开关系** +- Day 19:学校大会,程澈公开表白 +- Day 19下午:程澈父母正式接纳云想 +- Day 20:云想完美蜕变,成为风云人物 +- Day 20晚上:两人开始规划未来 + +关键转折点:公开关系,获得认可 +情感温度:稳定在100° + +--- + +【第10-12周 - 甜蜜日常】 + +**Day 21-25 - 第11集:幸福满溢** +- Day 21-23:校园甜蜜日常,撒糖不断 +- Day 24:两人规划大学和未来 +- Day 25:解决所有遗留问题,达成和解 + +关键转折点:进入稳定期,准备结局 +情感温度:持续100° + +--- + +【第16周 - 完美结局】 + +**毕业典礼日 - 第12集:永远幸福** +- 上午:毕业典礼,双双获得荣誉 +- 中午:程澈在典礼上浪漫求婚 +- 下午:云想含泪答应,全场祝福 +- 未来:携手走向美好人生 + +关键转折点:完美结局,永远幸福 +情感温度:达到巅峰120° + +==== 关键节点分析 ==== + +【情感升温节点】 +1. Day 1:初次相遇,保护关系建立(0°→30°) +2. Day 2-3:宠妻日常开启(30°→50°) +3. Day 4-5:占有欲爆发(50°→70°) +4. Day 9:确立恋爱关系(40°→90°) +5. Day 16:云想逆袭成功(80°→95°) +6. Day 18:生死考验后(20°→100°) + +【情感危机节点】 +1. Day 6:身份差距显现(70°→40°) +2. Day 11:情敌威胁(90°→60°) +3. Day 13:家族压力(85°→50°) +4. Day 17:生死危机(95°→20°) + +【重大转折节点】 +1. Day 1:命运相遇 +2. Day 6:身份曝光 +3. Day 9:确立关系 +4. Day 11:情敌出现 +5. Day 16:华丽逆袭 +6. Day 17:生死考验 +7. Day 19:公开宣示 +8. 毕业日:完美结局 + +==== 节奏控制策略 ==== + +【快节奏推进原则】 +- 每2-3天一个重大事件 +- 情感温度大起大落,制造过山车体验 +- 危机与甜蜜交替出现,保持观众情绪在线 + +【爽点分布密度】 +- 护短打脸:Day 1, 4, 11, 17 +- 宠妻甜蜜:Day 2, 9, 16, 21-25 +- 身份震撼:Day 1, 6, 17 +- 逆袭反击:Day 6, 16, 19 +- 占有宣示:Day 4, 12, 19 + +【钩子设置时机】 +每个重大事件结束时都设置强钩子: +- Day 1结尾:"以后跟着我,没人敢欺负你" +- Day 3结尾:神秘人要揭露程澈身份 +- Day 5结尾:程澈身份即将曝光 +- Day 7结尾:云想决定努力变优秀 +- Day 10结尾:程澈未婚妻出现 +- Day 12结尾:家族要断绝父子关系 +- Day 14结尾:云想隐藏天赋被发现 +- Day 16结尾:更大危机即将来临 +- Day 18结尾:两人感情更加坚定 +- Day 20结尾:开始规划美好未来 +- Day 25结尾:毕业典礼即将到来 + +==== 商业化时间节点 ==== + +【付费转化关键时刻】 +1. Day 4晚上:程澈吃醋大戏(第3集结尾) +2. Day 11下午:情敌对决高潮(第6集结尾) +3. Day 17晚上:生死营救(第9集结尾) +4. 毕业典礼:浪漫求婚(第12集结尾) + +【完播率保障节点】 +每集结尾的强钩子确保观众必须看下一集 + +==== 原著对比时间线 ==== + +【原著27集 vs 改编12集】 +- 原著1-9集内容 → 改编第1-2集(大幅压缩日常,突出冲突) +- 原著10-18集内容 → 改编第3-6集(强化情敌线,增加家族压力) +- 原著19-27集内容 → 改编第7-12集(新增生死考验,强化逆袭) + +【关键改动】 +1. 删除大量日常铺垫,直接进入冲突 +2. 前置音乐会情节,作为逆袭高光时刻 +3. 新增绑架营救情节,增强戏剧张力 +4. 压缩感情发展时间,快速确立关系 +5. 强化反派戏份,增加打脸爽点 + +==== 执行要点 ==== + +1. **严格按时间线执行**:确保每个关键节点按时到达 +2. **情感温度监控**:实时监控观众情绪,适时调整 +3. **钩子强度检验**:每个钩子都要能让观众"停不下来" +4. **节奏感把控**:快慢结合,张弛有度 +5. **商业节点重点**:付费转化时刻要重点打磨 + +这份时间线将确保我们的改编节奏紧凑,情节密集,每个关键节点都能最大化观众的情绪体验和商业价值。 \ No newline at end of file diff --git a/graph/__init__.py b/graph/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/graph/test_agent_graph_1.py b/graph/test_agent_graph_1.py new file mode 100644 index 0000000..b29ba02 --- /dev/null +++ b/graph/test_agent_graph_1.py @@ -0,0 +1,292 @@ +"""智能编剧系统工作流图定义 + +该模块定义了智能编剧系统的完整工作流程图,包括各个节点和边的连接关系。 +""" + +from typing import TypedDict, Annotated, Dict, Any, List, TypedDict, Optional +from agent.scheduler import SchedulerAgent +from agent.build_bible import BuildBibleAgent +from agent.episode_create import EpisodeCreateAgent +from agent.script_analysis import ScriptAnalysisAgent +from agent.strategic_planning import StrategicPlanningAgent + +from langgraph.graph import StateGraph, START, END +from utils.logger import get_logger +import operator + +logger = get_logger(__name__) + +# 定义一个简单的替换函数 +def replace_value(old_val, new_val): + """一个简单的合并函数,用于替换旧值""" + return new_val + +# 状态类型定义 +class InputState(TypedDict): + """工作流输入状态""" + input_data: Annotated[Dict[str, Any], operator.add] + session_id: Annotated[str, replace_value] + +class OutputState(TypedDict): + """工作流输出状态""" + session_id: Annotated[str, replace_value] + status: Annotated[str, replace_value] + error: Annotated[str, replace_value] + +class NodeInfo(TypedDict): + """工作流信息""" + step: Annotated[str, replace_value] # 阶段名称 [wait_for_input,script_analysis,strategic_planning,build_bible,episode_create_loop, finish] + status: Annotated[str, replace_value] # 当前阶段的状态 [waiting,running,failed,completed] + reason: Annotated[str, replace_value] # 失败原因 + retry_count: Annotated[int, replace_value] # 重试次数 + from_type: Annotated[str, replace_value] # 本次请求来着哪里 [user, agent] + + +class ScriptwriterState(TypedDict, total=False): + """智能编剧工作流整体状态""" + # 输入数据 + input_data: Annotated[Dict[str, Any], operator.add] + session_id: Annotated[str, replace_value] + + # 节点间状态 + node_info: NodeInfo + + # 中间状态 + agent_script_id: Annotated[str, replace_value] # 剧本ID 包括原文 + agent_plan: Annotated[Dict[str, Any], replace_value] #剧本计划 + script_bible: Annotated[Dict[str, Any], replace_value] #剧本圣经 + episode_list: Annotated[List, replace_value] # 章节列表 完成状态、产出章节id + + # 输出数据 + status: Annotated[str, replace_value] + error: Annotated[str, replace_value] + +class ScriptwriterGraph: + """智能编剧工作流图类 + + 管理智能编剧系统的完整工作流程,包括: + - 剧本接收 + - 诊断分析 + - 策略制定 + - 剧本圣经构建 + - 剧本创作 + - 迭代调整 + """ + + def __init__(self): + """初始化工作流图""" + self.graph = None + self._build_graph() + + + def node_router(self, state: ScriptwriterState) -> str: + next_node = state.get("node", '') + if next_node: + return next_node + else: + return END + + def _build_graph(self) -> None: + """构建工作流图""" + try: + # 创建智能体 + # 调度智能体 + schedulerAgent = SchedulerAgent( + tools=[], + SchedulerList=[ + { + "scheduler_node": "调度智能体节点", + "script_analysis_node": "原始剧本分析节点", + "strategic_planning_node": "确立改编目标节点", + "build_bible_node": "剧本圣经构建节点", + "episode_create_node": "单集创作节点", + "end_node": "结束节点,任务失败终止时使用,结束后整个工作流将停止" + } + ] + ) + scriptAnalysisAgent = ScriptAnalysisAgent( + tools=[], + SchedulerList=[ + { + "scheduler_node": "调度智能体节点", + } + ] + ) + strategicPlanningAgent = StrategicPlanningAgent( + tools=[], + SchedulerList=[ + { + "scheduler_node": "调度智能体节点", + } + ] + ) + buildBibleAgent = BuildBibleAgent( + tools=[], + SchedulerList=[ + { + "scheduler_node": "调度智能体节点", + } + ] + ) + episodeCreate = EpisodeCreateAgent( + tools=[], + SchedulerList=[ + { + "scheduler_node": "调度智能体节点", + } + ] + ) + + # 创建状态图 + workflow = StateGraph(ScriptwriterState, input_schema=InputState, output_schema=OutputState) + + # 添加节点 + workflow.add_node("scheduler_node", self.scheduler_node) + workflow.add_node("script_analysis_node", self.script_analysis_node) + workflow.add_node("strategic_planning_node", self.strategic_planning_node) + workflow.add_node("build_bible_node", self.build_bible_node) + workflow.add_node("episode_create_node", self.episode_create_node) + workflow.add_node("end_node", self.end_node) + + # 添加边 + workflow.set_entry_point("scheduler_node") + # 所有功能节点执行完成后,都返回给调度节点 + workflow.add_edge("script_analysis_node", "scheduler_node") + workflow.add_edge("strategic_planning_node", "scheduler_node") + workflow.add_edge("build_bible_node", "scheduler_node") + workflow.add_edge("episode_create_node", "scheduler_node") + + # 添加条件边:由调度节点决定下一个路由 + workflow.add_conditional_edges( + "scheduler_node", + self.node_router, + { + "script_analysis_node": "script_analysis_node", + "strategic_planning_node": "strategic_planning_node", + "build_bible_node": "build_bible_node", + "episode_create_node": "episode_create_node", + # 用户确认和暂停逻辑在这里处理,不需要单独的边 + "end_node": "end_node", + } + ) + + workflow.add_edge("end_node", END) + + # 编译图 + self.graph = workflow.compile() + logger.info("工作流图构建完成") + + except Exception as e: + logger.error(f"构建工作流图失败: {e}") + raise + + # --- 定义图中的节点 --- + async def scheduler_node(self, state: ScriptwriterState)-> ScriptwriterState: + """第一步:初步沟通,请求剧本""" + session_id = state.get("session_id", "") + + return {} + + async def script_analysis_node(self, state: ScriptwriterState)-> ScriptwriterState: + """第二步:诊断分析与资产评估""" + print("\n--- 正在进行诊断分析 ---") + session_id = state.get("session_id", "") + print(f"报告已生成: TEST") + return {} + + async def confirm_analysis_node(self, state: ScriptwriterState)-> ScriptwriterState: + """用户确认分析报告节点""" + print("\n等待用户确认分析报告...") + return {} + + async def strategic_planning_node(self, state: ScriptwriterState)-> ScriptwriterState: + """第三步:确立改编目标与战略蓝图""" + print("\n--- 正在制定战略蓝图 ---") + print(f"战略蓝图已生成: TEST") + return {} + + async def build_bible_node(self, state: ScriptwriterState)-> ScriptwriterState: + """第四步:确立改编目标与战略蓝图""" + print("\n--- 正在制定战略蓝图 ---") + print(f"战略蓝图已生成: TEST") + return {} + + + async def episode_create_node(self, state: ScriptwriterState)-> ScriptwriterState: + """第五步:动态创作与闭环校验(循环主体)""" + num_episodes = 3 # 假设每次创作3集 + episode_list = [] + return {"episode_list": episode_list} + + async def end_node(self, state: ScriptwriterState)-> OutputState: + """ 结束节点 处理并完成所有数据状态 """ + print(f"langgraph 所有任务完成") + return { + "session_id": state.get("session_id", ""), + "status": "", + "error": "", + } + + async def run(self, input_data: Dict[str, Any]) -> OutputState: + """运行工作流 + + Args: + input_data: 输入数据 + + Returns: + 工作流执行结果 + """ + try: + logger.info("开始运行智能编剧工作流") + + # # 初始化状态 + # initial_state: InputState = { + # 'input_data': input_data, + # 'session_id': input_data.get('session_id', ''), + # 'max_iterations': input_data.get('max_iterations', 3), + # 'batch_info': input_data.get('batch_info', {}) + # } + + # # 运行工作流 + # if self.graph is None: + # raise RuntimeError("工作流图未正确初始化") + + # result = await self.graph.ainvoke(initial_state) + # logger.info(f"工作流执行结果: {result}") + # if not result: + # raise ValueError("工作流执行结果为空") + # # 保存到记忆 + # self.memory.save_workflow_result(result) + + # # 构造输出状态 + # output_result: OutputState = { + # 'script': result.get('script'), + # 'adjustment': result.get('adjustment'), + # 'error': result.get('error'), + # 'iteration_count': result.get('iteration_count', 0) + # } + output_result:OutputState = { + 'session_id': "", + 'status': 'completed', + 'error': '', + } + logger.info("智能编剧工作流运行完成") + return output_result + + except Exception as e: + logger.error(f"运行工作流失败: {e}") + raise + + def get_graph_visualization(self) -> str: + """获取工作流图的可视化表示 + + Returns: + 图的文本表示 + """ + try: + if self.graph: + return str(self.graph) + return "工作流图未初始化" + except Exception as e: + logger.error(f"获取图可视化失败: {e}") + return f"获取图可视化失败: {e}" \ No newline at end of file diff --git a/graph/test_graph_3.py b/graph/test_graph_3.py new file mode 100644 index 0000000..4a32a1b --- /dev/null +++ b/graph/test_graph_3.py @@ -0,0 +1,171 @@ +# test_graph_persistent.py +from operator import add +from typing import TypedDict, Annotated +from langchain_core.messages import AnyMessage, HumanMessage +from langgraph import graph +from langgraph.config import get_stream_writer +from langgraph.constants import END, START +from langgraph.graph import StateGraph +from IPython.display import Image +import uuid +import config +# 导入数据库连接和自定义检查点存储器 +from tools.database.mongo import mainDB, client +# from mongodb_checkpointer import MongoDBCheckpointSaver +from langgraph.checkpoint.mongodb import MongoDBSaver +import asyncio +# collection = db.langgraph_checkpoints +memory: MongoDBSaver = MongoDBSaver(client, db_name=config.MONGO_CHECKPOINT_DB_NAME) + +class State(TypedDict): + messages: Annotated[list[AnyMessage], add] + type: str + +class InputState(TypedDict): + user_input: str + +class OutputState(TypedDict): + graph_output: str + +class OverallState(TypedDict): + foo: str + user_input: str + graph_output: str + +class PrivateState(TypedDict): + bar: str + +async def node_1(state: InputState) -> OverallState: + print(f"Node 1 处理: {state['user_input']}") + return {"foo": state["user_input"] + ">学院"} + +async def node_2(state: OverallState) -> PrivateState: + print(f"Node 2 处理: {state['foo']}") + return {"bar": state["foo"] + ">非常"} + +async def node_3(state: PrivateState) -> OverallState: + print(f"Node 3 处理: {state['bar']}") + return {"graph_output": state["bar"] + ">靠谱"} + +# 创建 MongoDB 检查点存储器 +# checkpointer = MongoDBCheckpointSaver(db.langgraph_checkpoints) + +# 构建图,并添加检查点存储器 +builder = StateGraph(OverallState, input_schema=InputState, output_schema=OutputState) + +builder.add_node('node_1', node_1) +builder.add_node('node_2', node_2) +builder.add_node('node_3', node_3) + +builder.add_edge(START, 'node_1') +builder.add_edge('node_1', 'node_2') +builder.add_edge('node_2', 'node_3') +builder.add_edge('node_3', END) + +# 编译图并添加检查点存储器 +graph = builder.compile(checkpointer=memory) + +async def run_with_persistence(user_input: str, thread_id: str = None): + """运行带持久化的图""" + if thread_id is None: + thread_id = str(uuid.uuid4()) + + print(f"使用线程 ID: {thread_id}") + + # 配置包含线程 ID + config = {"configurable": {"thread_id": thread_id}} + + # 执行图 + input_state = {"user_input": user_input} + output_state = await graph.ainvoke(input_state, config) + + print(f"输出: {output_state}") + return output_state, thread_id + +async def get_checkpoint_history(thread_id: str): + """获取检查点历史""" + config = {"configurable": {"thread_id": thread_id}} + + try: + history_generator = memory.list(config, limit=10) + + print("正在获取检查点历史...") + + # 使用列表推导式或 for 循环来收集所有检查点 + history = list(history_generator) + + print(f"找到 {len(history)} 个检查点:") + + for i, checkpoint_tuple in enumerate(history): + # checkpoint_tuple 包含 config, checkpoint, metadata 等属性 + # print(f" - ID: {checkpoint_tuple}") + checkpoint_data = checkpoint_tuple.checkpoint + metadata = checkpoint_tuple.metadata + print(f"检查点 {i+1}:") + print(f" - ID: {checkpoint_data.get('id', 'N/A')}") + print(f" - 状态: {checkpoint_data.get('channel_values', {})}") + print(f" - 元数据: {metadata}") + print("-" * 50) + + except Exception as e: + print(f"获取历史记录时出错: {e}") + +def resume_from_checkpoint(thread_id: str, checkpoint_id: str = None): + """从检查点恢复执行""" + config = {"configurable": {"thread_id": thread_id}} + + if checkpoint_id: + config["configurable"]["checkpoint_id"] = checkpoint_id + + try: + # 获取 CheckpointTuple 对象 + checkpoint_tuple = memory.get_tuple(config) + + if checkpoint_tuple: + # 直接通过属性访问,而不是解包 + checkpoint_data = checkpoint_tuple.checkpoint + metadata = checkpoint_tuple.metadata + print(f"从检查点恢复:") + print(f" - 检查点 ID: {checkpoint_data.get('id', 'N/A')}") + print(f" - 状态: {checkpoint_data.get('channel_values', {})}") + print(f" - 元数据: {metadata}") + return checkpoint_data.get('channel_values', {}) + else: + print(f"未找到线程 {thread_id} 的检查点") + return None + + except Exception as e: + print(f"恢复检查点时出错: {e}") + return None + +if __name__ == "__main__": + print("=== 测试持久化 LangGraph ===") + + # 第一次运行 + print("\n1. 第一次运行:") + # 由于在异步函数外使用await,需要使用asyncio运行 + output1, thread_id = asyncio.run(run_with_persistence("你好")) + + # 查看检查点历史 + print("\n2. 查看检查点历史:") + asyncio.run(get_checkpoint_history(thread_id)) + + # 从同一线程继续运行 + print("\n3. 从同一线程继续运行:") + output2, _ = asyncio.run(run_with_persistence("再见", thread_id)) + + # 查看更新后的历史 + print("\n4. 查看更新后的历史:") + asyncio.run(get_checkpoint_history(thread_id)) + + # 恢复检查点状态 + print("\n5. 恢复最新检查点状态:") + restored_state = resume_from_checkpoint(thread_id) + + # 可视化图结构(可选) + # try: + # with open('persistent_graph_visualization.png', 'wb') as f: + # f.write(graph.get_graph().draw_mermaid_png()) + # print("\n图片已保存为 persistent_graph_visualization.png") + # except Exception as e: + # print(f"保存可视化图片失败: {e}") \ No newline at end of file diff --git a/handlers/__init__.py b/handlers/__init__.py new file mode 100644 index 0000000..5039ec1 --- /dev/null +++ b/handlers/__init__.py @@ -0,0 +1,4 @@ +# handlers/__init__.py +""" +处理器模块初始化文件 +""" \ No newline at end of file diff --git a/handlers/langgraph_handler.py b/handlers/langgraph_handler.py new file mode 100644 index 0000000..feabc8c --- /dev/null +++ b/handlers/langgraph_handler.py @@ -0,0 +1,84 @@ +from flask import request, jsonify +import asyncio +import uuid +from graph.test_graph_3 import run_with_persistence, get_checkpoint_history, resume_from_checkpoint + +def run_async(coro): + """运行异步函数的辅助函数""" + try: + # 尝试使用现有的事件循环 + loop = asyncio.get_running_loop() + except RuntimeError: + # 如果没有运行中的事件循环,则创建一个新的 + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + return loop.run_until_complete(coro) + +def run_langgraph(): + """启动一个新的langgraph任务""" + try: + data = request.get_json() + user_input = data.get('user_input', '') + thread_id = data.get('thread_id', str(uuid.uuid4())) + + if not user_input: + return jsonify({'error': 'user_input is required'}), 400 + + # 运行异步函数 + output, thread_id = run_async(run_with_persistence(user_input, thread_id)) + + return jsonify({ + 'status': 'success', + 'thread_id': thread_id, + 'output': output + }) + except Exception as e: + return jsonify({'error': str(e)}), 500 + +def get_task_status(thread_id): + """查询任务状态和历史""" + try: + # 获取检查点历史 + # 注意:这里需要修改get_checkpoint_history以返回数据而不是打印 + # history = run_async(get_checkpoint_history(thread_id)) + + return jsonify({ + 'status': 'success', + 'thread_id': thread_id, + 'message': 'Task status endpoint' + }) + except Exception as e: + return jsonify({'error': str(e)}), 500 + +def resume_task(thread_id): + """从检查点恢复任务""" + try: + data = request.get_json() + checkpoint_id = data.get('checkpoint_id') + + # 恢复检查点状态 + restored_state = resume_from_checkpoint(thread_id, checkpoint_id) + + if restored_state: + return jsonify({ + 'status': 'success', + 'restored_state': restored_state + }) + else: + return jsonify({'error': 'Failed to restore checkpoint'}), 404 + except Exception as e: + return jsonify({'error': str(e)}), 500 + +def visualize_graph(thread_id): + """可视化图结构""" + try: + # 这里可以返回图的可视化信息 + # 为了简化,我们只返回基本信息 + return jsonify({ + 'status': 'success', + 'thread_id': thread_id, + 'message': 'Graph visualization endpoint' + }) + except Exception as e: + return jsonify({'error': str(e)}), 500 \ No newline at end of file diff --git a/models/__init__.py b/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/models/script_model.py b/models/script_model.py new file mode 100644 index 0000000..56546c7 --- /dev/null +++ b/models/script_model.py @@ -0,0 +1,397 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +会话数据模型 + +定义会话的数据结构和验证逻辑 +""" + +from datetime import datetime, timedelta +from typing import Dict, List, Optional, Any +from dataclasses import dataclass, field +from enum import Enum + +class SessionStatus(Enum): + """会话状态枚举""" + QUEUED = "queued" # 排队中 + PENDING = "pending" # 等待中 + ACTIVE = "active" # 活跃状态 + PAUSED = "paused" # 暂停状态 + COMPLETED = "completed" # 已完成 + CANCELLED = "cancelled" # 已取消 + ERROR = "error" # 错误状态 + +class SessionType(Enum): + """会话类型枚举""" + SCRIPTWRITING = "scriptwriting" # 编剧创作 + CONSULTATION = "consultation" # 咨询对话 + REVIEW = "review" # 剧本评审 + COLLABORATION = "collaboration" # 协作创作 + +@dataclass +class SessionModel: + """ + 会话数据模型 + + 定义会话的完整数据结构 + """ + + # 基础信息 + user_id: str + session_type: str = SessionType.SCRIPTWRITING.value + title: str = "" + description: str = "" + # 原始剧本内容 + original_script: str = "" + + # 状态信息 + status: str = SessionStatus.ACTIVE.value + current_step: int = 1 + total_steps: int = 6 + + # 配置信息 + settings: Dict[str, Any] = field(default_factory=dict) + metadata: Dict[str, Any] = field(default_factory=dict) + + # 时间信息 + created_at: datetime = field(default_factory=datetime.now) + updated_at: datetime = field(default_factory=datetime.now) + expires_at: datetime = field(default_factory=lambda: datetime.now() + timedelta(days=7)) + + # 可选字段 + session_id: Optional[str] = None + + def __post_init__(self): + """初始化后处理""" + # 验证数据 + self.validate() + + # 设置默认值 + if not self.title: + self.title = f"编剧会话 - {self.created_at.strftime('%Y-%m-%d %H:%M')}" + + # 确保设置字典存在必要的键 + default_settings = { + 'auto_save': True, + 'step_timeout': 1800, # 30分钟 + 'max_retries': 3, + 'language': 'zh-CN', + 'genre': 'drama', + 'style': 'modern' + } + + for key, value in default_settings.items(): + if key not in self.settings: + self.settings[key] = value + + # 确保元数据字典存在 + if 'tags' not in self.metadata: + self.metadata['tags'] = [] + if 'source' not in self.metadata: + self.metadata['source'] = 'web_interface' + + def validate(self) -> bool: + """ + 验证数据有效性 + + Returns: + bool: 是否有效 + + Raises: + ValueError: 数据无效时抛出异常 + """ + # 验证用户ID + if not self.user_id or not isinstance(self.user_id, str): + raise ValueError("用户ID不能为空且必须是字符串") + + # 验证会话类型 + valid_types = [t.value for t in SessionType] + if self.session_type not in valid_types: + raise ValueError(f"无效的会话类型: {self.session_type},有效值: {valid_types}") + + # 验证状态 + valid_statuses = [s.value for s in SessionStatus] + if self.status not in valid_statuses: + raise ValueError(f"无效的会话状态: {self.status},有效值: {valid_statuses}") + + # 验证步骤 + if not isinstance(self.current_step, int) or self.current_step < 1: + raise ValueError("当前步骤必须是大于0的整数") + + if not isinstance(self.total_steps, int) or self.total_steps < 1: + raise ValueError("总步骤数必须是大于0的整数") + + if self.current_step > self.total_steps: + raise ValueError("当前步骤不能超过总步骤数") + + # 验证时间 + if self.updated_at < self.created_at: + raise ValueError("更新时间不能早于创建时间") + + if self.expires_at <= self.created_at: + raise ValueError("过期时间必须晚于创建时间") + + return True + + def to_dict(self) -> Dict[str, Any]: + """ + 转换为字典格式 + + Returns: + Dict: 字典数据 + """ + data = { + 'user_id': self.user_id, + 'session_type': self.session_type, + 'title': self.title, + 'description': self.description, + 'original_script': self.original_script, + 'status': self.status, + 'current_step': self.current_step, + 'total_steps': self.total_steps, + 'settings': self.settings.copy(), + 'metadata': self.metadata.copy(), + 'created_at': self.created_at, + 'updated_at': self.updated_at, + 'expires_at': self.expires_at + } + + if self.session_id: + data['session_id'] = self.session_id + + return data + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> 'SessionModel': + """ + 从字典创建模型实例 + + Args: + data: 字典数据 + + Returns: + SessionModel: 模型实例 + """ + # 提取必需字段 + user_id = data.get('user_id') + if not user_id: + raise ValueError("缺少必需字段: user_id") + + # 创建实例 + instance = cls( + user_id=user_id, + session_type=data.get('session_type', SessionType.SCRIPTWRITING.value), + title=data.get('title', ''), + description=data.get('description', ''), + status=data.get('status', SessionStatus.ACTIVE.value), + current_step=data.get('current_step', 1), + total_steps=data.get('total_steps', 6), + settings=data.get('settings', {}), + metadata=data.get('metadata', {}) + ) + + # 设置时间字段 + if 'created_at' in data: + instance.created_at = data['created_at'] + if 'updated_at' in data: + instance.updated_at = data['updated_at'] + if 'expires_at' in data: + instance.expires_at = data['expires_at'] + + # 设置可选字段 + if 'session_id' in data: + instance.session_id = data['session_id'] + + return instance + + def update_status(self, new_status: str) -> None: + """ + 更新会话状态 + + Args: + new_status: 新状态 + """ + valid_statuses = [s.value for s in SessionStatus] + if new_status not in valid_statuses: + raise ValueError(f"无效的会话状态: {new_status}") + + self.status = new_status + self.updated_at = datetime.now() + + def advance_step(self) -> bool: + """ + 推进到下一步 + + Returns: + bool: 是否成功推进 + """ + if self.current_step < self.total_steps: + self.current_step += 1 + self.updated_at = datetime.now() + + # 如果到达最后一步,标记为完成 + if self.current_step == self.total_steps: + self.status = SessionStatus.COMPLETED.value + + return True + return False + + def reset_step(self, step_number: int) -> bool: + """ + 重置到指定步骤 + + Args: + step_number: 目标步骤号 + + Returns: + bool: 是否成功重置 + """ + if 1 <= step_number <= self.total_steps: + self.current_step = step_number + self.updated_at = datetime.now() + + # 如果从完成状态回退,更新状态 + if self.status == SessionStatus.COMPLETED.value and step_number < self.total_steps: + self.status = SessionStatus.ACTIVE.value + + return True + return False + + def update_setting(self, key: str, value: Any) -> None: + """ + 更新设置项 + + Args: + key: 设置键 + value: 设置值 + """ + self.settings[key] = value + self.updated_at = datetime.now() + + def add_metadata(self, key: str, value: Any) -> None: + """ + 添加元数据 + + Args: + key: 元数据键 + value: 元数据值 + """ + self.metadata[key] = value + self.updated_at = datetime.now() + + def add_tag(self, tag: str) -> None: + """ + 添加标签 + + Args: + tag: 标签名称 + """ + if 'tags' not in self.metadata: + self.metadata['tags'] = [] + + if tag not in self.metadata['tags']: + self.metadata['tags'].append(tag) + self.updated_at = datetime.now() + + def remove_tag(self, tag: str) -> bool: + """ + 移除标签 + + Args: + tag: 标签名称 + + Returns: + bool: 是否成功移除 + """ + if 'tags' in self.metadata and tag in self.metadata['tags']: + self.metadata['tags'].remove(tag) + self.updated_at = datetime.now() + return True + return False + + def extend_expiry(self, days: int = 7) -> None: + """ + 延长过期时间 + + Args: + days: 延长天数 + """ + self.expires_at = datetime.now() + timedelta(days=days) + self.updated_at = datetime.now() + + def is_expired(self) -> bool: + """ + 检查是否已过期 + + Returns: + bool: 是否已过期 + """ + return datetime.now() > self.expires_at + + def is_active(self) -> bool: + """ + 检查是否处于活跃状态 + + Returns: + bool: 是否活跃 + """ + return self.status == SessionStatus.ACTIVE.value and not self.is_expired() + + def is_completed(self) -> bool: + """ + 检查是否已完成 + + Returns: + bool: 是否已完成 + """ + return self.status == SessionStatus.COMPLETED.value or self.current_step >= self.total_steps + + def get_progress_percentage(self) -> float: + """ + 获取进度百分比 + + Returns: + float: 进度百分比 (0-100) + """ + if self.total_steps <= 0: + return 0.0 + + return min(100.0, (self.current_step / self.total_steps) * 100.0) + + def get_remaining_steps(self) -> int: + """ + 获取剩余步骤数 + + Returns: + int: 剩余步骤数 + """ + return max(0, self.total_steps - self.current_step) + + def get_session_duration(self) -> timedelta: + """ + 获取会话持续时间 + + Returns: + timedelta: 持续时间 + """ + return self.updated_at - self.created_at + + def __str__(self) -> str: + """ + 字符串表示 + + Returns: + str: 字符串描述 + """ + return f"SessionModel(id={self.session_id}, user={self.user_id}, step={self.current_step}/{self.total_steps}, status={self.status})" + + def __repr__(self) -> str: + """ + 详细字符串表示 + + Returns: + str: 详细描述 + """ + return (f"SessionModel(session_id={self.session_id}, user_id={self.user_id}, " + f"type={self.session_type}, title='{self.title}', status={self.status}, " + f"step={self.current_step}/{self.total_steps}, created={self.created_at})") \ No newline at end of file diff --git a/models/session_model.py b/models/session_model.py new file mode 100644 index 0000000..56546c7 --- /dev/null +++ b/models/session_model.py @@ -0,0 +1,397 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +会话数据模型 + +定义会话的数据结构和验证逻辑 +""" + +from datetime import datetime, timedelta +from typing import Dict, List, Optional, Any +from dataclasses import dataclass, field +from enum import Enum + +class SessionStatus(Enum): + """会话状态枚举""" + QUEUED = "queued" # 排队中 + PENDING = "pending" # 等待中 + ACTIVE = "active" # 活跃状态 + PAUSED = "paused" # 暂停状态 + COMPLETED = "completed" # 已完成 + CANCELLED = "cancelled" # 已取消 + ERROR = "error" # 错误状态 + +class SessionType(Enum): + """会话类型枚举""" + SCRIPTWRITING = "scriptwriting" # 编剧创作 + CONSULTATION = "consultation" # 咨询对话 + REVIEW = "review" # 剧本评审 + COLLABORATION = "collaboration" # 协作创作 + +@dataclass +class SessionModel: + """ + 会话数据模型 + + 定义会话的完整数据结构 + """ + + # 基础信息 + user_id: str + session_type: str = SessionType.SCRIPTWRITING.value + title: str = "" + description: str = "" + # 原始剧本内容 + original_script: str = "" + + # 状态信息 + status: str = SessionStatus.ACTIVE.value + current_step: int = 1 + total_steps: int = 6 + + # 配置信息 + settings: Dict[str, Any] = field(default_factory=dict) + metadata: Dict[str, Any] = field(default_factory=dict) + + # 时间信息 + created_at: datetime = field(default_factory=datetime.now) + updated_at: datetime = field(default_factory=datetime.now) + expires_at: datetime = field(default_factory=lambda: datetime.now() + timedelta(days=7)) + + # 可选字段 + session_id: Optional[str] = None + + def __post_init__(self): + """初始化后处理""" + # 验证数据 + self.validate() + + # 设置默认值 + if not self.title: + self.title = f"编剧会话 - {self.created_at.strftime('%Y-%m-%d %H:%M')}" + + # 确保设置字典存在必要的键 + default_settings = { + 'auto_save': True, + 'step_timeout': 1800, # 30分钟 + 'max_retries': 3, + 'language': 'zh-CN', + 'genre': 'drama', + 'style': 'modern' + } + + for key, value in default_settings.items(): + if key not in self.settings: + self.settings[key] = value + + # 确保元数据字典存在 + if 'tags' not in self.metadata: + self.metadata['tags'] = [] + if 'source' not in self.metadata: + self.metadata['source'] = 'web_interface' + + def validate(self) -> bool: + """ + 验证数据有效性 + + Returns: + bool: 是否有效 + + Raises: + ValueError: 数据无效时抛出异常 + """ + # 验证用户ID + if not self.user_id or not isinstance(self.user_id, str): + raise ValueError("用户ID不能为空且必须是字符串") + + # 验证会话类型 + valid_types = [t.value for t in SessionType] + if self.session_type not in valid_types: + raise ValueError(f"无效的会话类型: {self.session_type},有效值: {valid_types}") + + # 验证状态 + valid_statuses = [s.value for s in SessionStatus] + if self.status not in valid_statuses: + raise ValueError(f"无效的会话状态: {self.status},有效值: {valid_statuses}") + + # 验证步骤 + if not isinstance(self.current_step, int) or self.current_step < 1: + raise ValueError("当前步骤必须是大于0的整数") + + if not isinstance(self.total_steps, int) or self.total_steps < 1: + raise ValueError("总步骤数必须是大于0的整数") + + if self.current_step > self.total_steps: + raise ValueError("当前步骤不能超过总步骤数") + + # 验证时间 + if self.updated_at < self.created_at: + raise ValueError("更新时间不能早于创建时间") + + if self.expires_at <= self.created_at: + raise ValueError("过期时间必须晚于创建时间") + + return True + + def to_dict(self) -> Dict[str, Any]: + """ + 转换为字典格式 + + Returns: + Dict: 字典数据 + """ + data = { + 'user_id': self.user_id, + 'session_type': self.session_type, + 'title': self.title, + 'description': self.description, + 'original_script': self.original_script, + 'status': self.status, + 'current_step': self.current_step, + 'total_steps': self.total_steps, + 'settings': self.settings.copy(), + 'metadata': self.metadata.copy(), + 'created_at': self.created_at, + 'updated_at': self.updated_at, + 'expires_at': self.expires_at + } + + if self.session_id: + data['session_id'] = self.session_id + + return data + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> 'SessionModel': + """ + 从字典创建模型实例 + + Args: + data: 字典数据 + + Returns: + SessionModel: 模型实例 + """ + # 提取必需字段 + user_id = data.get('user_id') + if not user_id: + raise ValueError("缺少必需字段: user_id") + + # 创建实例 + instance = cls( + user_id=user_id, + session_type=data.get('session_type', SessionType.SCRIPTWRITING.value), + title=data.get('title', ''), + description=data.get('description', ''), + status=data.get('status', SessionStatus.ACTIVE.value), + current_step=data.get('current_step', 1), + total_steps=data.get('total_steps', 6), + settings=data.get('settings', {}), + metadata=data.get('metadata', {}) + ) + + # 设置时间字段 + if 'created_at' in data: + instance.created_at = data['created_at'] + if 'updated_at' in data: + instance.updated_at = data['updated_at'] + if 'expires_at' in data: + instance.expires_at = data['expires_at'] + + # 设置可选字段 + if 'session_id' in data: + instance.session_id = data['session_id'] + + return instance + + def update_status(self, new_status: str) -> None: + """ + 更新会话状态 + + Args: + new_status: 新状态 + """ + valid_statuses = [s.value for s in SessionStatus] + if new_status not in valid_statuses: + raise ValueError(f"无效的会话状态: {new_status}") + + self.status = new_status + self.updated_at = datetime.now() + + def advance_step(self) -> bool: + """ + 推进到下一步 + + Returns: + bool: 是否成功推进 + """ + if self.current_step < self.total_steps: + self.current_step += 1 + self.updated_at = datetime.now() + + # 如果到达最后一步,标记为完成 + if self.current_step == self.total_steps: + self.status = SessionStatus.COMPLETED.value + + return True + return False + + def reset_step(self, step_number: int) -> bool: + """ + 重置到指定步骤 + + Args: + step_number: 目标步骤号 + + Returns: + bool: 是否成功重置 + """ + if 1 <= step_number <= self.total_steps: + self.current_step = step_number + self.updated_at = datetime.now() + + # 如果从完成状态回退,更新状态 + if self.status == SessionStatus.COMPLETED.value and step_number < self.total_steps: + self.status = SessionStatus.ACTIVE.value + + return True + return False + + def update_setting(self, key: str, value: Any) -> None: + """ + 更新设置项 + + Args: + key: 设置键 + value: 设置值 + """ + self.settings[key] = value + self.updated_at = datetime.now() + + def add_metadata(self, key: str, value: Any) -> None: + """ + 添加元数据 + + Args: + key: 元数据键 + value: 元数据值 + """ + self.metadata[key] = value + self.updated_at = datetime.now() + + def add_tag(self, tag: str) -> None: + """ + 添加标签 + + Args: + tag: 标签名称 + """ + if 'tags' not in self.metadata: + self.metadata['tags'] = [] + + if tag not in self.metadata['tags']: + self.metadata['tags'].append(tag) + self.updated_at = datetime.now() + + def remove_tag(self, tag: str) -> bool: + """ + 移除标签 + + Args: + tag: 标签名称 + + Returns: + bool: 是否成功移除 + """ + if 'tags' in self.metadata and tag in self.metadata['tags']: + self.metadata['tags'].remove(tag) + self.updated_at = datetime.now() + return True + return False + + def extend_expiry(self, days: int = 7) -> None: + """ + 延长过期时间 + + Args: + days: 延长天数 + """ + self.expires_at = datetime.now() + timedelta(days=days) + self.updated_at = datetime.now() + + def is_expired(self) -> bool: + """ + 检查是否已过期 + + Returns: + bool: 是否已过期 + """ + return datetime.now() > self.expires_at + + def is_active(self) -> bool: + """ + 检查是否处于活跃状态 + + Returns: + bool: 是否活跃 + """ + return self.status == SessionStatus.ACTIVE.value and not self.is_expired() + + def is_completed(self) -> bool: + """ + 检查是否已完成 + + Returns: + bool: 是否已完成 + """ + return self.status == SessionStatus.COMPLETED.value or self.current_step >= self.total_steps + + def get_progress_percentage(self) -> float: + """ + 获取进度百分比 + + Returns: + float: 进度百分比 (0-100) + """ + if self.total_steps <= 0: + return 0.0 + + return min(100.0, (self.current_step / self.total_steps) * 100.0) + + def get_remaining_steps(self) -> int: + """ + 获取剩余步骤数 + + Returns: + int: 剩余步骤数 + """ + return max(0, self.total_steps - self.current_step) + + def get_session_duration(self) -> timedelta: + """ + 获取会话持续时间 + + Returns: + timedelta: 持续时间 + """ + return self.updated_at - self.created_at + + def __str__(self) -> str: + """ + 字符串表示 + + Returns: + str: 字符串描述 + """ + return f"SessionModel(id={self.session_id}, user={self.user_id}, step={self.current_step}/{self.total_steps}, status={self.status})" + + def __repr__(self) -> str: + """ + 详细字符串表示 + + Returns: + str: 详细描述 + """ + return (f"SessionModel(session_id={self.session_id}, user_id={self.user_id}, " + f"type={self.session_type}, title='{self.title}', status={self.status}, " + f"step={self.current_step}/{self.total_steps}, created={self.created_at})") \ No newline at end of file diff --git a/pyrightconfig.json b/pyrightconfig.json new file mode 100644 index 0000000..f58579c --- /dev/null +++ b/pyrightconfig.json @@ -0,0 +1,10 @@ +{ + "typeCheckingMode": "basic", + "reportUnknownMemberType": false, + "reportUnknownVariableType": false, + "reportUnknownArgumentType": false, + "reportMissingParameterType": false, + "reportMissingTypeArgument": false, + "reportUnknownParameterType": false, + "reportImplicitRelativeImport": false + } \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..aa01572 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,23 @@ +Flask +Flask-Cors +pymongo +python-dotenv +PyJWT +Werkzeug +dnspython +requests +oss2 +PyPDF2 +PyMuPDF +python-docx +openai +Pillow +tos +volcengine-python-sdk[ark] +volcengine[ark] +PyMySQL +DBUtils +PyMuPDF +langchain-community +langgraph +langgraph-checkpoint-mongodb \ No newline at end of file diff --git a/routes/__init__.py b/routes/__init__.py new file mode 100644 index 0000000..41cbd51 --- /dev/null +++ b/routes/__init__.py @@ -0,0 +1,4 @@ +# routes/__init__.py +""" +路由模块初始化文件 +""" \ No newline at end of file diff --git a/routes/langgraph_routes.py b/routes/langgraph_routes.py new file mode 100644 index 0000000..7f85119 --- /dev/null +++ b/routes/langgraph_routes.py @@ -0,0 +1,11 @@ +from flask import Blueprint +from handlers.langgraph_handler import run_langgraph, get_task_status, resume_task, visualize_graph + +# 创建蓝图 +bp = Blueprint('langgraph', __name__, url_prefix='/api/v1/langgraph') + +# 定义路由 +bp.add_url_rule('/run', view_func=run_langgraph, methods=['POST']) +bp.add_url_rule('/status/', view_func=get_task_status, methods=['GET']) +bp.add_url_rule('/resume/', view_func=resume_task, methods=['POST']) +bp.add_url_rule('/visualize/', view_func=visualize_graph, methods=['GET']) \ No newline at end of file diff --git a/tools/__init__.py b/tools/__init__.py new file mode 100644 index 0000000..5b6dbf0 --- /dev/null +++ b/tools/__init__.py @@ -0,0 +1,4 @@ +# tools/__init__.py +""" +工具模块初始化文件 +""" \ No newline at end of file diff --git a/tools/database/__init__.py b/tools/database/__init__.py new file mode 100644 index 0000000..db4d28c --- /dev/null +++ b/tools/database/__init__.py @@ -0,0 +1,11 @@ +# tools/database/__init__.py +""" +数据库工具模块初始化文件 +""" +# 从mongo.py导入常用的类或函数,方便其他模块导入 +try: + from .mongo import client, mainDB + __all__ = ['client', 'mainDB'] +except ImportError: + # 如果mongo模块无法导入,不抛出异常,保持包的基本功能 + pass \ No newline at end of file diff --git a/tools/database/mongo.py b/tools/database/mongo.py new file mode 100644 index 0000000..e8f611c --- /dev/null +++ b/tools/database/mongo.py @@ -0,0 +1,106 @@ +from pymongo import MongoClient +import config + +from pymongo.monitoring import (CommandListener, ServerListener, ConnectionPoolListener, + CommandSucceededEvent, CommandFailedEvent, + ServerHeartbeatStartedEvent, ServerHeartbeatSucceededEvent, ServerHeartbeatFailedEvent, + ConnectionCreatedEvent, ConnectionClosedEvent, ConnectionCheckOutStartedEvent, + ConnectionCheckedOutEvent, ConnectionCheckOutFailedEvent, ConnectionCheckedInEvent) + +# 命令事件监听器 +class MyCommandListener(CommandListener): + def started(self, event): + # print(f"Command {event.command_name} started on {event.connection_id}") + pass + + def succeeded(self, event: CommandSucceededEvent): + # print(f"Command {event.command_name} succeeded in {event.duration_micros} microseconds") + pass + + def failed(self, event: CommandFailedEvent): + print(f"Command {event.command_name} failed with error: {event.failure}") + +# 服务器事件监听器 +class MyServerListener(ServerListener): + def opened(self, event): + print(f"Server {event.server_address} opened") + + def description_changed(self, event): + # print(f"Server {event.previous_description.address} description changed to {event.new_description.address}") + pass + + def closed(self, event): + print(f"Server {event.server_address} closed") + + def heartbeat_started(self, event: ServerHeartbeatStartedEvent): + # print(f"Heartbeat started on server with id: {event.connection_id}") + pass + + def heartbeat_succeeded(self, event: ServerHeartbeatSucceededEvent): + # print(f"Heartbeat succeeded on server with id: {event.connection_id}") + pass + + def heartbeat_failed(self, event: ServerHeartbeatFailedEvent): + print(f"Heartbeat failed on server with id: {event.connection_id} with error: {event.reply}") + +# 连接池事件监听器 +class MyPoolListener(ConnectionPoolListener): + def pool_created(self, event): + print(f"Connection pool created for {event.address}") + + def pool_cleared(self, event): + print(f"Connection pool cleared for {event.address}") + + def pool_closed(self, event): + print(f"Connection pool closed for {event.address}") + + def connection_created(self, event: ConnectionCreatedEvent): + print(f"Connection {event.connection_id} created for {event.address}") + + def connection_ready(self, event): + print(f"Connection {event.connection_id} ready for {event.address}") + + def pool_ready(self, event): + print(f"Connection pool ready for {event.address}") + + def connection_closed(self, event: ConnectionClosedEvent): + print(f"Connection {event.connection_id} closed for {event.address}, reason: {event.reason}") + + def connection_check_out_started(self, event: ConnectionCheckOutStartedEvent): + # print(f"Connection check out started for {event.address}") + pass + + def connection_check_out_failed(self, event: ConnectionCheckOutFailedEvent): + print(f"Connection check out failed for {event.address}, reason: {event.reason}") + + def connection_checked_out(self, event: ConnectionCheckedOutEvent): + # print(f"Connection {event.connection_id} checked out for {event.address}") + pass + + def connection_checked_in(self, event: ConnectionCheckedInEvent): + # print(f"Connection {event.connection_id} checked in for {event.address}") + pass + + +# 实例化监听器 +command_listener = MyCommandListener() +server_listener = MyServerListener() +pool_listener = MyPoolListener() + +all_event_listeners = [command_listener, server_listener, pool_listener] + +MONGO_URI = config.MONGO_URI +DB_NAME = config.MONGO_MAIN_DB_NAME + +# 创建MongoDB客户端连接 +try: + # 实例化MongoClient时传入事件监听器 + client = MongoClient(MONGO_URI, event_listeners=all_event_listeners, serverSelectionTimeoutMS=5000) # 设置5秒超时 + mainDB = client[DB_NAME] + # 主动检查连接状态 + client.admin.command('ping') + success_message = f"\033[92m成功连接到MongoDB: {DB_NAME},事件监听器已激活。\033[0m" + print(success_message) +except Exception as e: + error_message = f"\033[91m数据库连接失败: {MONGO_URI},请检查MongoDB服务是否已启动。\033[0m" + print(error_message) \ No newline at end of file diff --git a/tools/database/mongodb_memory.py b/tools/database/mongodb_memory.py new file mode 100644 index 0000000..362f929 --- /dev/null +++ b/tools/database/mongodb_memory.py @@ -0,0 +1,30 @@ +"""工作流记忆管理模块 + +该模块负责管理智能编剧系统工作流的记忆存储和检索。 +""" + +import sys +import os +from typing import Dict, Any, List, Optional +from datetime import datetime +import json +from database import client # type: ignore +from langgraph.checkpoint.mongodb import MongoDBSaver + +# 添加项目根目录到路径 +sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))) +from agentgraph.utils.logger import get_logger + +logger = get_logger(__name__) + +DB_NAME = "langgraph_memory_db" + +class WorkflowMemory: + """工作流记忆管理类 + + 负责管理工作流执行过程中的状态存储、检索和历史记录。 + """ + + def __init__(self): + """初始化工作流记忆管理器""" + self.memory = MongoDBSaver(client, db_name=DB_NAME) diff --git a/tools/llm/__init__.py b/tools/llm/__init__.py new file mode 100644 index 0000000..13fe849 --- /dev/null +++ b/tools/llm/__init__.py @@ -0,0 +1,9 @@ +# tools/llm/__init__.py +""" +大语言模型工具模块初始化文件 +""" +from .huoshan_langchain import HuoshanChatModel + +__all__ = [ + 'HuoshanChatModel' +] \ No newline at end of file diff --git a/tools/llm/huoshan_langchain.py b/tools/llm/huoshan_langchain.py new file mode 100644 index 0000000..17d40d7 --- /dev/null +++ b/tools/llm/huoshan_langchain.py @@ -0,0 +1,137 @@ +from typing import Any, Dict, Iterator, List, Optional +from langchain_core.callbacks.manager import CallbackManagerForLLMRun +from langchain_core.language_models.chat_models import BaseChatModel +from langchain_core.messages import BaseMessage, AIMessage, HumanMessage, SystemMessage +from langchain_core.outputs import ChatGeneration, ChatResult +from pydantic import Field +from api.huoshan import HuoshanAPI # 导入你现有的API类 + + +class HuoshanChatModel(BaseChatModel): + """火山引擎聊天模型的LangChain封装""" + + # 模型配置参数 + model_name: str = Field(default="doubao-seed-1.6-250615", description="模型名称") + temperature: float = Field(default=0.6, description="温度参数") + max_tokens: int = Field(default=16384, description="最大token数") + + # 内部API实例 + _api: Optional[HuoshanAPI] = None + + def __init__(self, **kwargs): + super().__init__(**kwargs) + # 初始化火山引擎API实例 + self._api = HuoshanAPI() + + @property + def _llm_type(self) -> str: + """返回LLM类型标识""" + return "huoshan_chat" + + def _convert_messages_to_prompt(self, messages: List[BaseMessage]) -> tuple[str, str]: + """将LangChain消息格式转换为API所需的prompt和system格式""" + system_message = "" + user_messages = [] + + for message in messages: + if isinstance(message, SystemMessage): + system_message = message.content or "" + elif isinstance(message, HumanMessage): + user_messages.append(message.content) + elif isinstance(message, AIMessage): + # 如果需要支持多轮对话,可以在这里处理 + pass + + # 合并用户消息 + prompt = "\n".join(user_messages) if user_messages else "" + + return prompt, str(system_message) + + def _generate( + self, + messages: List[BaseMessage], + stop: Optional[List[str]] = None, + run_manager: Optional[CallbackManagerForLLMRun] = None, + **kwargs: Any, + ) -> ChatResult: + """生成聊天回复""" + if not self._api: + raise ValueError("HuoshanAPI未正确初始化") + + # 转换消息格式 + prompt, system = self._convert_messages_to_prompt(messages) + + # 合并参数 + generation_kwargs = { + "model": kwargs.get("model", self.model_name), + "temperature": kwargs.get("temperature", self.temperature), + "system": system + } + + try: + # 调用你的API + response_text = self._api.get_chat_response( + prompt=prompt, + **generation_kwargs + ) + + # 创建AI消息 + message = AIMessage(content=response_text) + + # 创建生成结果 + generation = ChatGeneration(message=message) + + return ChatResult(generations=[generation]) + + except Exception as e: + raise ValueError(f"调用火山引擎API失败: {str(e)}") + + def _stream( + self, + messages: List[BaseMessage], + stop: Optional[List[str]] = None, + run_manager: Optional[CallbackManagerForLLMRun] = None, + **kwargs: Any, + ) -> Iterator[ChatGeneration]: + """流式生成聊天回复""" + if not self._api: + raise ValueError("HuoshanAPI未正确初始化") + + # 转换消息格式 + prompt, system = self._convert_messages_to_prompt(messages) + + # 合并参数 + generation_kwargs = { + "model": kwargs.get("model", self.model_name), + "temperature": kwargs.get("temperature", self.temperature), + "system": system + } + + try: + # 调用流式API + for chunk in self._api.get_chat_response_stream( + prompt=prompt, + **generation_kwargs + ): + if chunk: + # 创建增量消息 + message = AIMessage(content=chunk) + generation = ChatGeneration(message=message) + + # 如果有回调管理器,通知新token + if run_manager: + run_manager.on_llm_new_token(chunk) + + yield generation + + except Exception as e: + raise ValueError(f"调用火山引擎流式API失败: {str(e)}") + + @property + def _identifying_params(self) -> Dict[str, Any]: + """返回用于标识模型的参数""" + return { + "model_name": self.model_name, + "temperature": self.temperature, + "max_tokens": self.max_tokens, + } \ No newline at end of file diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/utils/formatters.py b/utils/formatters.py new file mode 100644 index 0000000..3c36d61 --- /dev/null +++ b/utils/formatters.py @@ -0,0 +1,655 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +格式化器模块 + +提供响应格式化、数据转换和输出格式化功能 +""" + +import json +from datetime import datetime, date +from typing import Dict, List, Optional, Any, Union +from decimal import Decimal + +class ResponseFormatter: + """响应格式化器""" + + @staticmethod + def success_response(data: Any = None, message: str = "操作成功", + code: int = 200, extra: Dict[str, Any] = {}) -> Dict[str, Any]: + """ + 创建成功响应 + + Args: + data: 响应数据 + message: 响应消息 + code: 状态码 + extra: 额外信息 + + Returns: + Dict: 格式化的响应 + """ + response = { + "success": True, + "code": code, + "message": message, + "timestamp": datetime.now().isoformat(), + "data": data + } + + if extra: + response.update(extra) + + return response + + @staticmethod + def error_response(message: str = "操作失败", code: int = 400, + error_type: str = "ValidationError", + details: Dict[str, Any] = {}) -> Dict[str, Any]: + """ + 创建错误响应 + + Args: + message: 错误消息 + code: 错误码 + error_type: 错误类型 + details: 错误详情 + + Returns: + Dict: 格式化的错误响应 + """ + response = { + "success": False, + "code": code, + "message": message, + "error_type": error_type, + "timestamp": datetime.now().isoformat() + } + + if details: + response["details"] = details + + return response + + @staticmethod + def paginated_response(items: List[Any], total: int, page: int, + page_size: int, message: str = "查询成功") -> Dict[str, Any]: + """ + 创建分页响应 + + Args: + items: 数据项列表 + total: 总数量 + page: 当前页码 + page_size: 页大小 + message: 响应消息 + + Returns: + Dict: 格式化的分页响应 + """ + total_pages = (total + page_size - 1) // page_size + + pagination = { + "current_page": page, + "page_size": page_size, + "total_items": total, + "total_pages": total_pages, + "has_next": page < total_pages, + "has_prev": page > 1 + } + + return ResponseFormatter.success_response( + data={ + "items": items, + "pagination": pagination + }, + message=message + ) + + @staticmethod + def stream_response(data: Any, event_type: str = "data", + event_id: str = "") -> str: + """ + 创建流式响应 + + Args: + data: 响应数据 + event_type: 事件类型 + event_id: 事件ID + + Returns: + str: SSE格式的响应 + """ + lines = [] + + if event_id: + lines.append(f"id: {event_id}") + + lines.append(f"event: {event_type}") + + # 将数据转换为JSON字符串 + if isinstance(data, (dict, list)): + data_str = json.dumps(data, ensure_ascii=False, cls=DateTimeEncoder) + else: + data_str = str(data) + + lines.append(f"data: {data_str}") + lines.append("") # 空行表示事件结束 + + return "\n".join(lines) + + @staticmethod + def validation_error_response(errors: List[str], + warnings: List[str] = []) -> Dict[str, Any]: + """ + 创建验证错误响应 + + Args: + errors: 错误列表 + warnings: 警告列表 + + Returns: + Dict: 格式化的验证错误响应 + """ + details = {"errors": errors} + + if warnings: + details["warnings"] = warnings + + return ResponseFormatter.error_response( + message="数据验证失败", + code=422, + error_type="ValidationError", + details=details + ) + + @staticmethod + def not_found_response(resource: str = "资源") -> Dict[str, Any]: + """ + 创建资源未找到响应 + + Args: + resource: 资源名称 + + Returns: + Dict: 格式化的未找到响应 + """ + return ResponseFormatter.error_response( + message=f"{resource}未找到", + code=404, + error_type="NotFoundError" + ) + + @staticmethod + def unauthorized_response(message: str = "未授权访问") -> Dict[str, Any]: + """ + 创建未授权响应 + + Args: + message: 错误消息 + + Returns: + Dict: 格式化的未授权响应 + """ + return ResponseFormatter.error_response( + message=message, + code=401, + error_type="UnauthorizedError" + ) + + @staticmethod + def forbidden_response(message: str = "禁止访问") -> Dict[str, Any]: + """ + 创建禁止访问响应 + + Args: + message: 错误消息 + + Returns: + Dict: 格式化的禁止访问响应 + """ + return ResponseFormatter.error_response( + message=message, + code=403, + error_type="ForbiddenError" + ) + + @staticmethod + def rate_limit_response(retry_after: int = 60) -> Dict[str, Any]: + """ + 创建限流响应 + + Args: + retry_after: 重试等待时间(秒) + + Returns: + Dict: 格式化的限流响应 + """ + return ResponseFormatter.error_response( + message="请求过于频繁,请稍后重试", + code=429, + error_type="RateLimitError", + details={"retry_after": retry_after} + ) + + @staticmethod + def server_error_response(message: str = "服务器内部错误") -> Dict[str, Any]: + """ + 创建服务器错误响应 + + Args: + message: 错误消息 + + Returns: + Dict: 格式化的服务器错误响应 + """ + return ResponseFormatter.error_response( + message=message, + code=500, + error_type="InternalServerError" + ) + +class ErrorFormatter: + """错误格式化器""" + + @staticmethod + def format_exception(exception: Exception, include_traceback: bool = False) -> Dict[str, Any]: + """ + 格式化异常信息 + + Args: + exception: 异常对象 + include_traceback: 是否包含堆栈跟踪 + + Returns: + Dict: 格式化的异常信息 + """ + error_info = { + "type": exception.__class__.__name__, + "message": str(exception), + "timestamp": datetime.now().isoformat() + } + + if include_traceback: + import traceback + error_info["traceback"] = traceback.format_exc() + + return error_info + + @staticmethod + def format_validation_errors(errors: List[str], field_errors: Dict[str, List[str]] = {}) -> Dict[str, Any]: + """ + 格式化验证错误 + + Args: + errors: 通用错误列表 + field_errors: 字段特定错误字典 + + Returns: + Dict: 格式化的验证错误 + """ + formatted = { + "general_errors": errors, + "error_count": len(errors) + } + + if field_errors: + formatted["field_errors"] = field_errors + formatted["error_count"] += sum(len(errs) for errs in field_errors.values()) + + return formatted + + @staticmethod + def format_database_error(error: Exception) -> Dict[str, Any]: + """ + 格式化数据库错误 + + Args: + error: 数据库异常 + + Returns: + Dict: 格式化的数据库错误 + """ + error_message = str(error) + + # 根据错误类型提供更友好的消息 + if "duplicate key" in error_message.lower(): + user_message = "数据已存在,请检查唯一性约束" + elif "foreign key" in error_message.lower(): + user_message = "关联数据不存在,请检查数据完整性" + elif "not null" in error_message.lower(): + user_message = "必填字段不能为空" + elif "timeout" in error_message.lower(): + user_message = "数据库操作超时,请稍后重试" + else: + user_message = "数据库操作失败" + + return { + "type": "DatabaseError", + "user_message": user_message, + "technical_message": error_message, + "timestamp": datetime.now().isoformat() + } + +class DataFormatter: + """数据格式化器""" + + @staticmethod + def format_session_data(session_data: Dict[str, Any]) -> Dict[str, Any]: + """ + 格式化会话数据 + + Args: + session_data: 原始会话数据 + + Returns: + Dict: 格式化的会话数据 + """ + formatted = { + "session_id": session_data.get("session_id"), + "user_id": session_data.get("user_id"), + "session_type": session_data.get("session_type"), + "status": session_data.get("status"), + "current_step": session_data.get("current_step", 1), + "created_at": DataFormatter._format_datetime(session_data.get("created_at")), + "updated_at": DataFormatter._format_datetime(session_data.get("updated_at")), + "expires_at": DataFormatter._format_datetime(session_data.get("expires_at")) + } + + # 添加可选字段 + optional_fields = ["title", "description", "session_config", "metadata"] + for field in optional_fields: + if field in session_data: + formatted[field] = session_data[field] + + return formatted + + @staticmethod + def format_step_data(step_data: Dict[str, Any]) -> Dict[str, Any]: + """ + 格式化步骤数据 + + Args: + step_data: 原始步骤数据 + + Returns: + Dict: 格式化的步骤数据 + """ + formatted = { + "step_id": step_data.get("step_id"), + "session_id": step_data.get("session_id"), + "step_number": step_data.get("step_number"), + "step_type": step_data.get("step_type"), + "status": step_data.get("status"), + "execution_mode": step_data.get("execution_mode", "sync"), + "started_at": DataFormatter._format_datetime(step_data.get("started_at")), + "completed_at": DataFormatter._format_datetime(step_data.get("completed_at")), + "created_at": DataFormatter._format_datetime(step_data.get("created_at")) + } + + # 添加执行结果 + if "result_data" in step_data: + formatted["result_data"] = step_data["result_data"] + + # 添加错误信息 + if "error_message" in step_data: + formatted["error_message"] = step_data["error_message"] + + # 计算执行时长 + if step_data.get("started_at") and step_data.get("completed_at"): + start_time = step_data["started_at"] + end_time = step_data["completed_at"] + if isinstance(start_time, datetime) and isinstance(end_time, datetime): + duration = (end_time - start_time).total_seconds() + formatted["execution_duration_seconds"] = duration + + return formatted + + @staticmethod + def format_workflow_state_data(state_data: Dict[str, Any]) -> Dict[str, Any]: + """ + 格式化工作流状态数据 + + Args: + state_data: 原始状态数据 + + Returns: + Dict: 格式化的状态数据 + """ + formatted = { + "state_id": state_data.get("state_id"), + "session_id": state_data.get("session_id"), + "state_type": state_data.get("state_type"), + "status": state_data.get("status"), + "priority": state_data.get("priority"), + "created_at": DataFormatter._format_datetime(state_data.get("created_at")), + "updated_at": DataFormatter._format_datetime(state_data.get("updated_at")), + "expires_at": DataFormatter._format_datetime(state_data.get("expires_at")) + } + + # 添加状态特定数据 + if "state_data" in state_data: + formatted["state_data"] = state_data["state_data"] + + # 添加可选字段 + optional_fields = ["category", "related_step", "assigned_to", "processed_by", "processed_at"] + for field in optional_fields: + if field in state_data: + if field == "processed_at": + formatted[field] = DataFormatter._format_datetime(state_data[field]) + else: + formatted[field] = state_data[field] + + return formatted + + @staticmethod + def format_memory_data(memory_data: Dict[str, Any]) -> Dict[str, Any]: + """ + 格式化记忆数据 + + Args: + memory_data: 原始记忆数据 + + Returns: + Dict: 格式化的记忆数据 + """ + formatted = { + "memory_id": memory_data.get("memory_id"), + "user_id": memory_data.get("user_id"), + "memory_type": memory_data.get("memory_type"), + "memory_key": memory_data.get("memory_key"), + "category": memory_data.get("category"), + "access_level": memory_data.get("access_level"), + "importance": memory_data.get("importance"), + "weight": memory_data.get("weight"), + "access_count": memory_data.get("access_count", 0), + "created_at": DataFormatter._format_datetime(memory_data.get("created_at")), + "updated_at": DataFormatter._format_datetime(memory_data.get("updated_at")) + } + + # 添加记忆数据(可能需要脱敏) + if "memory_data" in memory_data: + formatted["memory_data"] = DataFormatter._sanitize_memory_data( + memory_data["memory_data"], + memory_data.get("sensitivity", "low") + ) + + # 添加可选字段 + optional_fields = ["description", "tags", "last_accessed", "expires_at"] + for field in optional_fields: + if field in memory_data: + if field in ["last_accessed", "expires_at"]: + formatted[field] = DataFormatter._format_datetime(memory_data[field]) + else: + formatted[field] = memory_data[field] + + return formatted + + @staticmethod + def format_list_response(items: List[Dict[str, Any]], + formatter_func, + total: int = 0, + page: int = 0, + page_size: int = 0) -> Dict[str, Any]: + """ + 格式化列表响应 + + Args: + items: 数据项列表 + formatter_func: 格式化函数 + total: 总数量 + page: 页码 + page_size: 页大小 + + Returns: + Dict: 格式化的列表响应 + """ + formatted_items = [formatter_func(item) for item in items] + + result:Any = {"items": formatted_items} + + if total > 0: + result["total"] = total + + if page > 0 and page_size > 0: + result["pagination"] = { + "current_page": page, + "page_size": page_size, + "total_pages": (total + page_size - 1) // page_size if total else 1 + } + + return result + + @staticmethod + def _format_datetime(dt: Union[datetime, str, None]) -> Optional[str]: + """ + 格式化日期时间 + + Args: + dt: 日期时间对象或字符串 + + Returns: + Optional[str]: 格式化的日期时间字符串 + """ + if dt is None: + return None + + if isinstance(dt, datetime): + return dt.isoformat() + + if isinstance(dt, str): + return dt + + return str(dt) + + @staticmethod + def _sanitize_memory_data(memory_data: Dict[str, Any], sensitivity: str) -> Dict[str, Any]: + """ + 根据敏感度脱敏记忆数据 + + Args: + memory_data: 记忆数据 + sensitivity: 敏感度级别 + + Returns: + Dict: 脱敏后的数据 + """ + if sensitivity in ["high", "confidential"]: + # 高敏感度数据需要脱敏 + sanitized = {} + for key, value in memory_data.items(): + if key in ["password", "token", "secret", "private_key"]: + sanitized[key] = "***" + elif isinstance(value, str) and len(value) > 10: + # 长字符串部分脱敏 + sanitized[key] = value[:3] + "***" + value[-3:] + else: + sanitized[key] = value + return sanitized + + return memory_data.copy() + +class DateTimeEncoder(json.JSONEncoder): + """自定义JSON编码器,处理日期时间对象""" + + def default(self, obj): + if isinstance(obj, datetime): + return obj.isoformat() + elif isinstance(obj, date): + return obj.isoformat() + elif isinstance(obj, Decimal): + return float(obj) + return super().default(obj) + +def format_file_size(size_bytes: int) -> str: + """ + 格式化文件大小 + + Args: + size_bytes: 字节数 + + Returns: + str: 格式化的文件大小 + """ + if size_bytes == 0: + return "0 B" + + size_names = ["B", "KB", "MB", "GB", "TB"] + import math + i = int(math.floor(math.log(size_bytes, 1024))) + p = math.pow(1024, i) + s = round(size_bytes / p, 2) + return f"{s} {size_names[i]}" + +def format_duration(seconds: float) -> str: + """ + 格式化持续时间 + + Args: + seconds: 秒数 + + Returns: + str: 格式化的持续时间 + """ + if seconds < 60: + return f"{seconds:.2f}秒" + elif seconds < 3600: + minutes = seconds / 60 + return f"{minutes:.2f}分钟" + else: + hours = seconds / 3600 + return f"{hours:.2f}小时" + +def truncate_text(text: str, max_length: int = 100, suffix: str = "...") -> str: + """ + 截断文本 + + Args: + text: 原始文本 + max_length: 最大长度 + suffix: 后缀 + + Returns: + str: 截断后的文本 + """ + if len(text) <= max_length: + return text + + return text[:max_length - len(suffix)] + suffix + +def mask_sensitive_info(text: str, mask_char: str = "*", visible_chars: int = 3) -> str: + """ + 遮蔽敏感信息 + + Args: + text: 原始文本 + mask_char: 遮蔽字符 + visible_chars: 可见字符数 + + Returns: + str: 遮蔽后的文本 + """ + if len(text) <= visible_chars * 2: + return mask_char * len(text) + + return text[:visible_chars] + mask_char * (len(text) - visible_chars * 2) + text[-visible_chars:] \ No newline at end of file diff --git a/utils/logger.py b/utils/logger.py new file mode 100644 index 0000000..d11bcdc --- /dev/null +++ b/utils/logger.py @@ -0,0 +1,58 @@ +import logging +import os +import sys +from logging.handlers import RotatingFileHandler + +def get_logger(name): + """ + 获取统一配置的logger实例 + + Args: + name: logger名称,通常使用 __name__ + + Returns: + logging.Logger: 配置好的logger实例 + """ + logger = logging.getLogger(name) + + # 如果logger已经配置过,直接返回 + if logger.handlers: + return logger + + # 设置日志级别 + logger.setLevel(logging.INFO) + + # 创建日志目录 + log_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'logs') + os.makedirs(log_dir, exist_ok=True) + + # 创建日志格式 + formatter = logging.Formatter( + '%(asctime)s - %(name)s - %(levelname)s - %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' + ) + + # 文件处理器 - 使用轮转日志 + log_file = os.path.join(log_dir, 'langgraph.log') + file_handler = RotatingFileHandler( + log_file, + maxBytes=10*1024*1024, # 10MB + backupCount=5, + encoding='utf-8' + ) + file_handler.setLevel(logging.INFO) + file_handler.setFormatter(formatter) + + # 控制台处理器 + console_handler = logging.StreamHandler(sys.stdout) + console_handler.setLevel(logging.INFO) + console_handler.setFormatter(formatter) + + # 添加处理器 + logger.addHandler(file_handler) + logger.addHandler(console_handler) + + # 防止日志向上传播 + logger.propagate = False + + return logger \ No newline at end of file