优化
This commit is contained in:
parent
d378a24f94
commit
6fb23d35ea
3
config/config.ini
Normal file
3
config/config.ini
Normal file
@ -0,0 +1,3 @@
|
||||
[test]
|
||||
DASHSCOPE_API_KEY=sk-063b48fffb914d558ddcddc5166fd34d
|
||||
[pro]
|
119
main.py
119
main.py
@ -1,122 +1,67 @@
|
||||
from fastapi import FastAPI, Query
|
||||
import uvicorn
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.responses import FileResponse
|
||||
import uvicorn, os
|
||||
from utils.music_analysis import music_analysis, chat_analysis
|
||||
import requests
|
||||
from utils.response import success_response, error_400_response, error_503_response
|
||||
from utils.music_analysis import music_analysis
|
||||
import os
|
||||
from utils.response import success_response, error_response
|
||||
|
||||
app = FastAPI(title="douyin文档", swagger_ui_parameters={
|
||||
"defaultModelsExpandDepth": -1
|
||||
})
|
||||
|
||||
DEFAULT_PC_VIDEO_URL = 'https://v.douyin.com/-NvlqBdIJo4/'
|
||||
DEFAULT_mobile_VIDEO_URL = 'https://v.douyin.com/BCfMrTFPYGQ/'
|
||||
ENVIRONMENT = os.getenv("ENVIRONMENT", "test")
|
||||
host = '127.0.0.1:9579'
|
||||
host = 'http://127.0.0.1:9579'
|
||||
if ENVIRONMENT == "pro":
|
||||
host = 'http://douyin_tiktok_download_api:80'
|
||||
|
||||
|
||||
@app.get('/douyin_video', tags=["抖音"], summary="返回视屏信息,最全的接口了")
|
||||
def douyin_video(video_url: str = Query(DEFAULT_mobile_VIDEO_URL, min_length=10)):
|
||||
print(video_url)
|
||||
@app.post('/douyin', tags=["抖音"], summary="分享链接获取抖音详细信息")
|
||||
async def douyin(request: Request):
|
||||
os.environ["DASHSCOPE_API_KEY"] = "sk-063b48fffb914d558ddcddc5166fd34d"
|
||||
form_data = await request.form()
|
||||
video_url = form_data.get('video_url', '').strip()
|
||||
print(f'原始视频url为:{video_url}')
|
||||
if not video_url:
|
||||
return {"code": 400, "message": "An error occurred.", "data": "请指定video_url"}
|
||||
return error_response(400, data='video_url 参数缺失')
|
||||
elif len(video_url) < 21:
|
||||
return error_response(400, data='video_url 参数长度不够')
|
||||
video_url = chat_analysis(video_url)
|
||||
print(f'截取后视频url为:{video_url}')
|
||||
if not video_url:
|
||||
return error_response(400, data='解析不到url')
|
||||
elif len(video_url) < 21:
|
||||
return error_response(400, data='解析到的url长度不够')
|
||||
|
||||
# 获取get请求参数
|
||||
url = host + "/api/hybrid/video_data"
|
||||
print(url)
|
||||
|
||||
querystring = {"url": video_url, "minimal": "true"}
|
||||
response = requests.request("GET", url, params=querystring)
|
||||
print(response.text)
|
||||
print(response.json()['data']['music']['play_url'])
|
||||
|
||||
try:
|
||||
if response.json()['code'] == 200:
|
||||
video_url = response.json()['data']['video_data']['wm_video_url']
|
||||
video_music = response.json()['data']['music']['play_url']['url_list'][0]
|
||||
content = music_analysis(video_music)
|
||||
return success_response({"video_url": video_url, "video_music": video_music, "content": content
|
||||
return success_response(200, data={"video_url": video_url, "video_music": video_music, "content": content
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return error_400_response({"data": "解析字段失败."})
|
||||
return error_response(400, data='解析字段失败')
|
||||
|
||||
return error_503_response({"data": "抖音风控稍后请求."})
|
||||
return error_response(500, data='其他异常')
|
||||
|
||||
|
||||
@app.get('/douyin_content', tags=["抖音"], summary="手机和pc获取文案")
|
||||
def douyin_content(video_url: str = Query(DEFAULT_mobile_VIDEO_URL, min_length=10)):
|
||||
print(video_url)
|
||||
if not video_url:
|
||||
return {"code": 400, "message": "An error occurred.", "data": "请指定video_url"}
|
||||
|
||||
# 获取get请求参数
|
||||
url = host + "/api/hybrid/video_data"
|
||||
|
||||
querystring = {"url": video_url, "minimal": "false"}
|
||||
response = requests.request("GET", url, params=querystring)
|
||||
print(response.text)
|
||||
@app.get('/')
|
||||
def index():
|
||||
try:
|
||||
if response.json()['code'] == 200:
|
||||
return success_response({"content": response.json()['data']['seo_info']['ocr_content'],
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return error_400_response({"data": "解析字段失败."})
|
||||
|
||||
return error_503_response({"data": "抖音风控稍后请求."})
|
||||
|
||||
|
||||
@app.get('/douyin_pc', tags=["抖音"], summary="返回pc文案和视频")
|
||||
def douyin_pc(video_url: str = Query(DEFAULT_PC_VIDEO_URL, min_length=10)):
|
||||
print(video_url)
|
||||
if not video_url:
|
||||
return {"code": 400, "message": "An error occurred.", "data": "请指定video_url"}
|
||||
|
||||
# 获取get请求参数
|
||||
url = host + "/api/hybrid/video_data"
|
||||
|
||||
querystring = {"url": video_url, "minimal": "false"}
|
||||
response = requests.request("GET", url, params=querystring)
|
||||
print(response.text)
|
||||
try:
|
||||
if response.json()['code'] == 200:
|
||||
return success_response({"content": response.json()['data']['seo_info']['ocr_content'],
|
||||
"pc_url": response.json()['data']['video']['bit_rate'][0]['play_addr']['url_list']
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return error_400_response({"data": "解析字段失败."})
|
||||
|
||||
return error_503_response({"data": "抖音风控稍后请求."})
|
||||
|
||||
|
||||
@app.get('/douyin_phone', tags=["抖音"], summary="返回手机视屏地址")
|
||||
def douyin_phone(video_url: str = Query(DEFAULT_mobile_VIDEO_URL, min_length=10)):
|
||||
print(video_url)
|
||||
if not video_url:
|
||||
return {"code": 400, "message": "An error occurred.", "data": "请指定video_url"}
|
||||
|
||||
# 获取get请求参数
|
||||
url = host + "/api/hybrid/video_data"
|
||||
|
||||
querystring = {"url": video_url, "minimal": "true"}
|
||||
response = requests.request("GET", url, params=querystring)
|
||||
print(response.text)
|
||||
try:
|
||||
if response.json()['code'] == 200:
|
||||
return success_response({"phone_url": response.json()['data']['video_data']['wm_video_url']
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return error_400_response({"data": "解析字段失败."})
|
||||
|
||||
return error_503_response({"data": "抖音风控稍后请求."})
|
||||
return FileResponse('templates/index.html')
|
||||
except FileNotFoundError:
|
||||
return {'error': 'index.html 文件未找到'}, 404
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
133
templates/index.html
Normal file
133
templates/index.html
Normal file
@ -0,0 +1,133 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>抖音视频解析助手</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Poppins', sans-serif;
|
||||
background: linear-gradient(135deg, #f3e7e9 0%, #e3eeff 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.glow-box {
|
||||
box-shadow: 0 0 30px rgba(99, 102, 241, 0.1);
|
||||
}
|
||||
|
||||
.multi-line-ellipsis {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 5;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 1.5em;
|
||||
max-height: 7.5em;
|
||||
transition: max-height 0.3s ease;
|
||||
}
|
||||
|
||||
.multi-line-ellipsis:hover {
|
||||
-webkit-line-clamp: unset;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="flex items-center justify-center p-4">
|
||||
<div class="w-full max-w-2xl bg-white rounded-2xl p-8 glow-box">
|
||||
<h1 class="text-3xl font-bold text-indigo-600 mb-6 text-center">
|
||||
🎥 抖音视频解析器
|
||||
</h1>
|
||||
|
||||
<div class="space-y-6">
|
||||
<div class="relative">
|
||||
<input
|
||||
type="text"
|
||||
id="videoUrl"
|
||||
placeholder="粘贴抖音视频链接..."
|
||||
class="w-full px-4 py-3 rounded-lg border-2 border-indigo-100 focus:border-indigo-400 focus:ring-2 focus:ring-indigo-200 transition-all"
|
||||
>
|
||||
<button
|
||||
onclick="fetchVideoInfo()"
|
||||
class="absolute right-2 top-2 bg-gradient-to-r from-indigo-500 to-purple-600 text-white px-6 py-2 rounded-md hover:scale-105 transition-transform"
|
||||
>
|
||||
立即解析
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="resultContainer" class="hidden">
|
||||
<div class="bg-gray-50 p-6 rounded-xl animate-fade-in space-y-4">
|
||||
<h3 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
|
||||
<svg class="w-6 h-6 mr-2 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
解析结果
|
||||
</h3>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<!-- 视频地址 -->
|
||||
<div class="bg-white p-4 rounded-lg shadow-sm">
|
||||
<label class="text-indigo-600 font-medium block mb-2">视频地址</label>
|
||||
<a id="videoUrlLink" target="_blank"
|
||||
class="text-blue-600 break-all hover:underline hover:text-blue-800 transition-colors">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- 背景音乐 -->
|
||||
<div class="bg-white p-4 rounded-lg shadow-sm">
|
||||
<label class="text-purple-600 font-medium block mb-2">背景音乐</label>
|
||||
<a id="musicUrlLink" target="_blank"
|
||||
class="text-blue-600 break-all hover:underline hover:text-blue-800 transition-colors">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- 视频文案 -->
|
||||
<div class="bg-white p-4 rounded-lg shadow-sm">
|
||||
<label class="text-green-600 font-medium block mb-2">视频文案</label>
|
||||
<div id="contentText" class="text-gray-700 leading-relaxed multi-line-ellipsis scrollbar-thin scrollbar-thumb-gray-300 scrollbar-track-gray-100">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function fetchVideoInfo() {
|
||||
const url = document.getElementById('videoUrl').value;
|
||||
const resultContainer = document.getElementById('resultContainer');
|
||||
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('video_url', url);
|
||||
|
||||
const response = await fetch('/douyin', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
const responseData = await response.json();
|
||||
|
||||
if (responseData.code === 200) {
|
||||
// 填充结构化数据
|
||||
document.getElementById('videoUrlLink').href = responseData.data.video_url;
|
||||
document.getElementById('videoUrlLink').textContent = responseData.data.video_url;
|
||||
|
||||
document.getElementById('musicUrlLink').href = responseData.data.video_music;
|
||||
document.getElementById('musicUrlLink').textContent = responseData.data.video_music;
|
||||
|
||||
document.getElementById('contentText').textContent = responseData.data.content;
|
||||
resultContainer.classList.remove('hidden');
|
||||
} else {
|
||||
alert(`错误代码 ${responseData.code}: ${responseData.message}`);
|
||||
}
|
||||
} catch (error) {
|
||||
alert('解析失败,请检查链接有效性');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
17
utils/__init__.py
Normal file
17
utils/__init__.py
Normal file
@ -0,0 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
from configparser import ConfigParser
|
||||
|
||||
ENVIRONMENT=os.getenv("ENVIRONMENT", "test")
|
||||
print(f"当前环境为:{ENVIRONMENT}")
|
||||
conf = ConfigParser()
|
||||
path=os.path.dirname(__file__).replace("\\utils", "")
|
||||
conf.read(f"{path}\\config\\config.ini")
|
||||
config = conf[ENVIRONMENT]
|
||||
# 遍历conf
|
||||
for k, v in config.items():
|
||||
config[k] = v.strip()
|
||||
os.environ[k] = v.strip()
|
||||
|
||||
print(f"加载配置文件完成")
|
||||
|
@ -6,7 +6,12 @@ import requests
|
||||
import os
|
||||
from openai import OpenAI
|
||||
|
||||
dashscope.api_key = os.getenv("DASHSCOPE_API_KEY","*****")
|
||||
dashscope.api_key = os.getenv("DASHSCOPE_API_KEY", "*****")
|
||||
content = """
|
||||
将文本的链接提取出来,只留链接的有效信息
|
||||
# 输出
|
||||
只输出链接不需要分析过程
|
||||
"""
|
||||
|
||||
|
||||
def music_analysis(music_url):
|
||||
@ -22,7 +27,7 @@ def music_analysis(music_url):
|
||||
transcribe_response = Transcription.fetch(task=transcribe_response.output.task_id)
|
||||
|
||||
if transcribe_response.status_code == HTTPStatus.OK:
|
||||
url=transcribe_response.output['results'][0]['transcription_url']
|
||||
url = transcribe_response.output['results'][0]['transcription_url']
|
||||
print(url)
|
||||
|
||||
# 发送GET请求
|
||||
@ -40,11 +45,12 @@ def music_analysis(music_url):
|
||||
print(f"请求失败,状态码:{response.status_code}")
|
||||
return text
|
||||
|
||||
|
||||
def chat_analysis(video_url):
|
||||
text=''
|
||||
text = ''
|
||||
client = OpenAI(
|
||||
# 若没有配置环境变量,请用百炼API Key将下行替换为:api_key="sk-xxx",
|
||||
api_key=os.getenv("DASHSCOPE_API_KEY","*****"),
|
||||
api_key=os.getenv("DASHSCOPE_API_KEY", "*****"),
|
||||
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
|
||||
)
|
||||
completion = client.chat.completions.create(
|
||||
@ -53,20 +59,19 @@ def chat_analysis(video_url):
|
||||
messages=[
|
||||
{
|
||||
'role': 'system',
|
||||
'content': """
|
||||
将文本的链接提取出来,只留链接的有效信息
|
||||
# 输出
|
||||
只输出链接不需要分析过程
|
||||
"""
|
||||
'content': content
|
||||
},
|
||||
{'role': 'user', 'content': video_url}],
|
||||
)
|
||||
|
||||
print(completion.model_dump())
|
||||
print(f'语言模型返回数据: {completion.model_dump()}')
|
||||
for choices in completion.model_dump()['choices']:
|
||||
text+=choices['message']['content']
|
||||
text += choices['message']['content']
|
||||
return text
|
||||
|
||||
def video_url(video_url):
|
||||
print(video_url)
|
||||
if __name__ == '__main__':
|
||||
# music_analysis('https://lf26-music-east.douyinstatic.com/obj/ies-music-hj/7494207652008839996.mp3')
|
||||
chat_analysis('4.17 复制打开抖音,看看【三维地球科普的作品】河南省最奇怪的城市——信阳市 # 信阳市 # 河南... https://v.douyin.com/RBU9atEeafc/ AGI:/ i@p.QX 11/14 ')
|
||||
|
||||
chat_analysis(
|
||||
'原始视频url为:9.79 复制打开抖音,看看【学钓鱼的佳琪的作品】少与人纠缠,多跟鱼拉扯 # dou是钓鱼人 # 爱... https://v.douyin.com/1skvRRYPEgA/ DHI:/ n@D.uf 05/06')
|
||||
|
@ -1,54 +1,33 @@
|
||||
from fastapi import status
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
def success_response(data: dict = None, message: str = "Success"):
|
||||
|
||||
def success_response(code: int = 200, data: dict = None,
|
||||
http_status: int = status.HTTP_200_OK):
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_200_OK,
|
||||
status_code=http_status,
|
||||
content={
|
||||
"code": 200,
|
||||
"message": message,
|
||||
"data": data or {}
|
||||
"code": code,
|
||||
"message": "success",
|
||||
"data": data
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def error_response(
|
||||
code: int = 400,
|
||||
message: str = "Error",
|
||||
http_status: int = status.HTTP_400_BAD_REQUEST
|
||||
):
|
||||
return JSONResponse(
|
||||
status_code=http_status,
|
||||
content={
|
||||
"code": code,
|
||||
"message": message,
|
||||
"data": None
|
||||
}
|
||||
)
|
||||
|
||||
def error_400_response(
|
||||
code: int = 400,
|
||||
message: dict = None,
|
||||
http_status: int = status.HTTP_400_BAD_REQUEST
|
||||
):
|
||||
return JSONResponse(
|
||||
status_code=http_status,
|
||||
content={
|
||||
"code": code,
|
||||
"message": message,
|
||||
"data": None
|
||||
}
|
||||
)
|
||||
|
||||
def error_503_response(
|
||||
code: int = 503,
|
||||
message: dict = None,
|
||||
data: dict = None,
|
||||
http_status: int = status.HTTP_503_SERVICE_UNAVAILABLE
|
||||
):
|
||||
return JSONResponse(
|
||||
status_code=http_status,
|
||||
content={
|
||||
"code": code,
|
||||
"message": message,
|
||||
"data": None
|
||||
"message": "fail",
|
||||
"data": data
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(error_response())
|
||||
|
Loading…
x
Reference in New Issue
Block a user