Kaynağa Gözat

代码上传

lalala 1 yıl önce
işleme
944bc1eb30

+ 8 - 0
.idea/deepface.iml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="PYTHON_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="jdk" jdkName="Python 3.8 (deepface_new)" jdkType="Python SDK" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 39 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,39 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
+      <option name="ignoredPackages">
+        <value>
+          <list size="10">
+            <item index="0" class="java.lang.String" itemvalue="pen_up" />
+            <item index="1" class="java.lang.String" itemvalue="0000000000" />
+            <item index="2" class="java.lang.String" itemvalue="ccccccc000" />
+            <item index="3" class="java.lang.String" itemvalue="a0a0000000" />
+            <item index="4" class="java.lang.String" itemvalue="bbbb000000" />
+            <item index="5" class="java.lang.String" itemvalue="end" />
+            <item index="6" class="java.lang.String" itemvalue="aaa0000000" />
+            <item index="7" class="java.lang.String" itemvalue="000c000000" />
+            <item index="8" class="java.lang.String" itemvalue="tips" />
+            <item index="9" class="java.lang.String" itemvalue="pen_down" />
+          </list>
+        </value>
+      </option>
+    </inspection_tool>
+    <inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
+      <option name="ignoredErrors">
+        <list>
+          <option value="N806" />
+          <option value="N803" />
+          <option value="N802" />
+        </list>
+      </option>
+    </inspection_tool>
+    <inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
+      <option name="ignoredIdentifiers">
+        <list>
+          <option value="dict.*" />
+        </list>
+      </option>
+    </inspection_tool>
+  </profile>
+</component>

+ 6 - 0
.idea/inspectionProfiles/profiles_settings.xml

@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+  <settings>
+    <option name="USE_PROJECT_PROFILE" value="false" />
+    <version value="1.0" />
+  </settings>
+</component>

+ 7 - 0
.idea/misc.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (deepface_new)" project-jdk-type="Python SDK" />
+  <component name="PyCharmProfessionalAdvertiser">
+    <option name="shown" value="true" />
+  </component>
+</project>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/deepface.iml" filepath="$PROJECT_DIR$/.idea/deepface.iml" />
+    </modules>
+  </component>
+</project>

+ 116 - 0
.idea/workspace.xml

@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="AutoImportSettings">
+    <option name="autoReloadType" value="SELECTIVE" />
+  </component>
+  <component name="ChangeListManager">
+    <list default="true" id="34ce3608-afdb-4c42-92df-beb7b6073931" name="变更" comment="" />
+    <option name="SHOW_DIALOG" value="false" />
+    <option name="HIGHLIGHT_CONFLICTS" value="true" />
+    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
+    <option name="LAST_RESOLUTION" value="IGNORE" />
+  </component>
+  <component name="MarkdownSettingsMigration">
+    <option name="stateVersion" value="1" />
+  </component>
+  <component name="ProjectId" id="2uCkAPoLAq3Ca8lRWI3iYv7ui89" />
+  <component name="ProjectViewState">
+    <option name="hideEmptyMiddlePackages" value="true" />
+    <option name="showLibraryContents" value="true" />
+  </component>
+  <component name="PropertiesComponent">{
+  &quot;keyToString&quot;: {
+    &quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
+    &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
+    &quot;last_opened_file_path&quot;: &quot;D:/ANACINDA/envs/deepface_new&quot;,
+    &quot;settings.editor.selected.configurable&quot;: &quot;com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable&quot;
+  }
+}</component>
+  <component name="RecentsManager">
+    <key name="MoveFile.RECENT_KEYS">
+      <recent name="C:\Users\Administrator\Desktop\deepface" />
+    </key>
+  </component>
+  <component name="RunManager" selected="Python.main">
+    <configuration name="main" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
+      <module name="deepface" />
+      <option name="INTERPRETER_OPTIONS" value="" />
+      <option name="PARENT_ENVS" value="true" />
+      <envs>
+        <env name="PYTHONUNBUFFERED" value="1" />
+      </envs>
+      <option name="SDK_HOME" value="" />
+      <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
+      <option name="IS_MODULE_SDK" value="true" />
+      <option name="ADD_CONTENT_ROOTS" value="true" />
+      <option name="ADD_SOURCE_ROOTS" value="true" />
+      <option name="SCRIPT_NAME" value="$PROJECT_DIR$/main.py" />
+      <option name="PARAMETERS" value="" />
+      <option name="SHOW_COMMAND_LINE" value="false" />
+      <option name="EMULATE_TERMINAL" value="false" />
+      <option name="MODULE_MODE" value="false" />
+      <option name="REDIRECT_INPUT" value="false" />
+      <option name="INPUT_FILE" value="" />
+      <method v="2" />
+    </configuration>
+    <configuration name="speech_synthesis" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
+      <module name="deepface" />
+      <option name="INTERPRETER_OPTIONS" value="" />
+      <option name="PARENT_ENVS" value="true" />
+      <envs>
+        <env name="PYTHONUNBUFFERED" value="1" />
+      </envs>
+      <option name="SDK_HOME" value="" />
+      <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
+      <option name="IS_MODULE_SDK" value="true" />
+      <option name="ADD_CONTENT_ROOTS" value="true" />
+      <option name="ADD_SOURCE_ROOTS" value="true" />
+      <option name="SCRIPT_NAME" value="$PROJECT_DIR$/speech_synthesis.py" />
+      <option name="PARAMETERS" value="" />
+      <option name="SHOW_COMMAND_LINE" value="false" />
+      <option name="EMULATE_TERMINAL" value="false" />
+      <option name="MODULE_MODE" value="false" />
+      <option name="REDIRECT_INPUT" value="false" />
+      <option name="INPUT_FILE" value="" />
+      <method v="2" />
+    </configuration>
+    <configuration name="upload_file" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
+      <module name="deepface" />
+      <option name="INTERPRETER_OPTIONS" value="" />
+      <option name="PARENT_ENVS" value="true" />
+      <envs>
+        <env name="PYTHONUNBUFFERED" value="1" />
+      </envs>
+      <option name="SDK_HOME" value="" />
+      <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
+      <option name="IS_MODULE_SDK" value="true" />
+      <option name="ADD_CONTENT_ROOTS" value="true" />
+      <option name="ADD_SOURCE_ROOTS" value="true" />
+      <option name="SCRIPT_NAME" value="$PROJECT_DIR$/upload_file.py" />
+      <option name="PARAMETERS" value="" />
+      <option name="SHOW_COMMAND_LINE" value="false" />
+      <option name="EMULATE_TERMINAL" value="false" />
+      <option name="MODULE_MODE" value="false" />
+      <option name="REDIRECT_INPUT" value="false" />
+      <option name="INPUT_FILE" value="" />
+      <method v="2" />
+    </configuration>
+    <recent_temporary>
+      <list>
+        <item itemvalue="Python.speech_synthesis" />
+        <item itemvalue="Python.upload_file" />
+      </list>
+    </recent_temporary>
+  </component>
+  <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="应用程序级" UseSingleDictionary="true" transferred="true" />
+  <component name="TaskManager">
+    <task active="true" id="Default" summary="默认任务">
+      <changelist id="34ce3608-afdb-4c42-92df-beb7b6073931" name="变更" comment="" />
+      <created>1741759799821</created>
+      <option name="number" value="Default" />
+      <option name="presentableId" value="Default" />
+      <updated>1741759799821</updated>
+    </task>
+    <servers />
+  </component>
+</project>

+ 19 - 0
Dockerfile

@@ -0,0 +1,19 @@
+# 使用 Python 3.8.0 作为基础镜像
+FROM python:3.8
+
+# 设置工作目录
+WORKDIR /app
+
+# 复制当前目录下的所有文件到工作目录
+COPY . /app
+
+RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple/
+RUN apt-get update && apt-get install -y libgl1
+# 安装依赖
+RUN pip install --no-cache-dir -r requirements.txt
+
+# 暴露端口
+EXPOSE 2002
+
+# 运行应用程序
+CMD ["python", "main.py"]

BIN
__pycache__/speech_synthesis_factory.cpython-38.pyc


BIN
__pycache__/upload_file.cpython-38.pyc


BIN
__pycache__/video_handler.cpython-38.pyc


+ 93 - 0
main.py

@@ -0,0 +1,93 @@
+from flask import Flask, request, jsonify
+from upload_file import OSSUploader
+import os
+from video_handler import process_video, merge_videos
+from speech_synthesis_factory import TtsClientWrapper
+import azure.cognitiveservices.speech as speechsdk
+import time
+
+
+app = Flask(__name__)
+
+oss_uploader = OSSUploader()
+
+
+@app.route('/tts', methods=['POST'])
+def tts_process():
+    print(request.get_json())
+    data = request.get_json()
+    if 'code' not in data:
+        return jsonify({"error": "Missing 'code' in request data"}), 400
+    if 'text' not in data:
+        return jsonify({"error": "Missing 'text' in request data"}), 400
+    tts_wrapper = TtsClientWrapper()
+    code = data['code']
+    text = data['text']
+    synthesizer = tts_wrapper.getTtsClient(code)
+    speech_synthesis_result = synthesizer.speak_text_async(text).get()
+    if speech_synthesis_result.reason == speechsdk.ResultReason.SynthesizingAudioCompleted:
+        audio_data_stream = speechsdk.AudioDataStream(speech_synthesis_result)
+        timestamp = int(time.time())
+        temp_file_path = f'tts_{timestamp}.wav'
+        audio_data_stream.save_to_wav_file(temp_file_path)
+        video_path = oss_uploader.upload_video_to_oss_local(temp_file_path)
+        # 删除临时文件
+        if os.path.exists(temp_file_path):
+            os.remove(temp_file_path)
+        print(video_path)
+        return video_path
+    else:
+        return jsonify({"error": f"Speech synthesis failed: {speech_synthesis_result.error_details}"})
+
+
+@app.route('/deepface', methods=['POST'])
+def deepface_process():
+    print(request.get_json())
+    video_paths = []
+    try:
+        data = request.get_json()
+        if 'video_urls' not in data:
+            return jsonify({"error": "Missing 'video_urls' in request data"}), 400
+        video_urls = data['video_urls']
+        # 分别处理每个视频URL
+        emotion_dicts = []
+        for url in video_urls:
+            emotion_dict, video_path = process_video(url.split("?")[0])
+            emotion_dicts.append(emotion_dict)
+            video_paths.append(video_path)
+
+        # 合并标注好的视频
+        merged_video_path = merge_videos(video_paths)
+        # 合并情绪字典
+        merged_emotion_dict = {}
+        for d in emotion_dicts:
+            for emotion, count in d.items():
+                if emotion in merged_emotion_dict:
+                    merged_emotion_dict[emotion] += count
+                else:
+                    merged_emotion_dict[emotion] = count
+
+        # 计算总帧数
+        total_frames = sum(sum(d.values()) for d in emotion_dicts)
+
+        # 计算每种情绪的百分比并保留整数部分
+        emotion_percentage_dict = {}
+        for emotion, count in merged_emotion_dict.items():
+            percentage = int((count / total_frames) * 100)
+            emotion_percentage_dict[emotion] = percentage
+
+        merged_video_path = oss_uploader.upload_video_to_oss_local(merged_video_path)
+        response = {
+            "emotion_percentage_dict": emotion_percentage_dict,
+            "merged_video_path": merged_video_path
+        }
+        return jsonify(response)
+    finally:
+        # 删除中间产生的标注视频
+        for video_path in video_paths:
+            if os.path.exists(video_path):
+                os.remove(video_path)
+
+
+if __name__ == '__main__':
+    app.run(host='0.0.0.0', port=2002, debug=True)

BIN
requirements.txt


+ 20 - 0
speech_synthesis_factory.py

@@ -0,0 +1,20 @@
+
+import azure.cognitiveservices.speech as speechsdk
+
+
+class TtsClientWrapper:
+    def __init__(self):
+        self.speech_key = "DzMBKYw2oVnL7brsyLZYlpvOqhiCDshlzRqQNtDOrwJA6KL5DOdcJQQJ99BCAC3pKaRXJ3w3AAAYACOGDWcJ"
+        self.speech_region = "eastasia"
+        self.voice_map = {
+            0: "en-GB-OllieMultilingualNeural",
+            1: "en-US-BrandonMultilingualNeural",
+            2: "en-GB-AdaMultilingualNeural",
+            3: "en-US-AmandaMultilingualNeural"
+        }
+
+    def getTtsClient(self, code):
+        speech_config = speechsdk.SpeechConfig(subscription=self.speech_key, region=self.speech_region)
+        speech_config.speech_synthesis_voice_name = self.voice_map[code]
+        synthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config, audio_config=None)
+        return synthesizer

+ 68 - 0
upload_file.py

@@ -0,0 +1,68 @@
+import oss2
+import os
+
+oss_bucket_name = 'eai-files'
+oss_endpoint = 'oss-cn-shanghai.aliyuncs.com'
+access_key_id = 'LTAI5tAbkw8rkreiJbfcY1jZ'
+access_key_secret = '2yvtVYE1qAZEgm0ChvdMqhp0LhB5Lj'
+
+
+class OSSUploader:
+    def __init__(self):
+
+        self.bucket_name = 'eai-files'
+        self.endpoint = 'oss-cn-shanghai.aliyuncs.com'
+        self.access_key_id = 'LTAI5tAbkw8rkreiJbfcY1jZ'
+        self.access_key_secret = '2yvtVYE1qAZEgm0ChvdMqhp0LhB5Lj'
+        # 初始化 OSS 认证和 Bucket 对象
+        self.auth = oss2.Auth(self.access_key_id, self.access_key_secret)
+        self.bucket = oss2.Bucket(self.auth, self.endpoint, self.bucket_name)
+
+    def upload_video_to_oss_local(self, local_video_path):
+        """
+        上传本地视频文件到 OSS
+        :param local_video_path: 本地视频文件路径
+        :return: OSS 文件 URL(如果上传成功),否则返回 None
+        """
+        try:
+            # 提取本地视频文件名
+            video_filename = os.path.basename(local_video_path)
+
+            # 上传视频文件到 OSS
+            result = self.bucket.put_object_from_file(video_filename, local_video_path)
+
+            if result.status == 200:
+                # 生成公共读的访问 URL
+                oss_url = f"https://{self.bucket_name}.{self.endpoint}/{video_filename}"
+
+                # 删除本地视频文件
+                os.remove(local_video_path)
+                print(f"已成功删除本地视频文件: {local_video_path}")
+                return oss_url
+            else:
+                print(f"上传失败,状态码: {result.status}")
+                return None
+        except Exception as e:
+            print(f"上传过程中出现错误: {e}")
+            return None
+
+    def upload_video_to_oss_stream(self, data_stream, object_name):
+        """
+        上传数据流到 OSS
+        :param data_stream: 数据流(字节流或文件流)
+        :param object_name: OSS 中的对象名称
+        :return: OSS 文件 URL(如果上传成功),否则返回 None
+        """
+        try:
+            # 上传数据流到 OSS
+            result = self.bucket.put_object(object_name, data_stream)
+            if result.status == 200:
+                # 生成公共读的访问 URL
+                oss_url = f"https://{self.bucket_name}.{self.endpoint}/{object_name}"
+                return oss_url
+            else:
+                print(f"上传失败,状态码: {result.status}")
+                return None
+        except Exception as e:
+            print(f"上传过程中出现错误: {e}")
+            return None

+ 82 - 0
video_handler.py

@@ -0,0 +1,82 @@
+import cv2
+from deepface import DeepFace
+import time
+from moviepy.editor import VideoFileClip, concatenate_videoclips
+
+
+def process_video(video_url):
+    # 打开视频流
+    cap = cv2.VideoCapture(video_url)
+    # 检查视频是否成功打开
+    if not cap.isOpened():
+        print("Error opening video stream from URL")
+        return {}, None
+
+    # 获取视频的帧率、宽度和高度
+    fps = cap.get(cv2.CAP_PROP_FPS)
+    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
+    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
+
+    # 获取当前时间戳
+    timestamp = int(time.time())
+
+    # 定义视频编码器和创建视频写入对象,使用MP4格式
+    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
+    # 在输出文件名中加入时间戳
+    output_path = f'annotated_video_{timestamp}.mp4'
+    out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
+
+    # 初始化情绪字典
+    emotion_dict = {}
+
+    frame_count = 0
+    current_emotion = None
+
+    # 循环读取视频帧
+    while cap.isOpened():
+        ret, frame = cap.read()
+        if not ret:
+            break
+
+        if frame_count % 20 == 0:
+            try:
+                # 使用DeepFace进行情绪识别
+                result = DeepFace.analyze(frame, actions=['emotion'], enforce_detection=False)
+                current_emotion = result[0]['dominant_emotion']
+
+                # 更新情绪字典
+                if current_emotion in emotion_dict:
+                    emotion_dict[current_emotion] += 1
+                else:
+                    emotion_dict[current_emotion] = 1
+
+            except Exception as e:
+                print(f"Error processing frame: {e}")
+
+        if current_emotion is not None:
+            # 在帧上显示情绪信息
+            cv2.putText(frame, f"Emotion: {current_emotion}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
+
+        # 写入标注后的帧到输出视频
+        out.write(frame)
+        frame_count += 1
+
+    # 释放视频捕获对象和写入对象
+    cap.release()
+    out.release()
+
+    return emotion_dict, output_path
+
+
+def merge_videos(video_paths):
+    clips = []
+    try:
+        clips = [VideoFileClip(p) for p in video_paths]
+        final = concatenate_videoclips(clips)
+        output = f'merged_video_{int(time.time())}.mp4'
+        final.write_videofile(output, threads=4, codec='libx264')
+        return output
+    finally:
+        for clip in clips:
+            clip.close()
+        time.sleep(0.5)  # 额外等待