parent
77aff56530
commit
d91da23a3f
24 changed files with 868 additions and 1 deletions
@ -0,0 +1,3 @@ |
||||
from django.contrib import admin |
||||
|
||||
# Register your models here. |
||||
@ -0,0 +1,6 @@ |
||||
from django.apps import AppConfig |
||||
|
||||
|
||||
class ShowAiConfig(AppConfig): |
||||
default_auto_field = 'django.db.models.BigAutoField' |
||||
name = 'ai' |
||||
@ -0,0 +1,51 @@ |
||||
# Generated by Django 4.2.7 on 2026-06-08 07:20 |
||||
|
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
initial = True |
||||
|
||||
dependencies = [ |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.CreateModel( |
||||
name='AiShow', |
||||
fields=[ |
||||
('id', models.AutoField(primary_key=True, serialize=False)), |
||||
('cinema', models.CharField(max_length=50)), |
||||
('zz_code', models.CharField(max_length=50)), |
||||
('show_date', models.DateField()), |
||||
('is_ai_show', models.BooleanField(default=True)), |
||||
('show', models.TextField()), |
||||
('sales', models.CharField(max_length=50)), |
||||
('prompt', models.TextField()), |
||||
('result', models.TextField()), |
||||
('message', models.TextField()), |
||||
('created_at', models.DateTimeField(auto_now_add=True)), |
||||
], |
||||
options={ |
||||
'verbose_name': 'AI排片数据', |
||||
'verbose_name_plural': 'AI排片数据', |
||||
'db_table': 'ai_show_result', |
||||
}, |
||||
), |
||||
migrations.CreateModel( |
||||
name='TestCinema', |
||||
fields=[ |
||||
('id', models.AutoField(primary_key=True, serialize=False)), |
||||
('name', models.CharField(max_length=50)), |
||||
('zz_code', models.CharField(max_length=50)), |
||||
('db_config', models.TextField()), |
||||
('user_config', models.TextField()), |
||||
('is_active', models.BooleanField(default=True)), |
||||
], |
||||
options={ |
||||
'verbose_name': '测试影院', |
||||
'verbose_name_plural': '测试影院', |
||||
'db_table': 'ai_show_cinema', |
||||
}, |
||||
), |
||||
] |
||||
@ -0,0 +1,23 @@ |
||||
# Generated by Django 4.2.7 on 2026-06-08 10:37 |
||||
|
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('ai', '0001_initial'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AddField( |
||||
model_name='aishow', |
||||
name='take_times', |
||||
field=models.IntegerField(default=0), |
||||
), |
||||
migrations.AddField( |
||||
model_name='aishow', |
||||
name='take_tokens', |
||||
field=models.CharField(default='', max_length=2000), |
||||
), |
||||
] |
||||
@ -0,0 +1,28 @@ |
||||
# Generated by Django 4.2.7 on 2026-06-09 02:00 |
||||
|
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('ai', '0002_aishow_take_times_aishow_take_tokens'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.CreateModel( |
||||
name='PromptTemplate', |
||||
fields=[ |
||||
('id', models.AutoField(primary_key=True, serialize=False)), |
||||
('prompt_type', models.CharField(max_length=50)), |
||||
('prompt_key', models.CharField(max_length=50)), |
||||
('prompt_val', models.TextField()), |
||||
('del_flag', models.BooleanField(default=False)), |
||||
], |
||||
options={ |
||||
'verbose_name': '提示词', |
||||
'verbose_name_plural': '提示词', |
||||
'db_table': 'ai_prompt_template', |
||||
}, |
||||
), |
||||
] |
||||
@ -0,0 +1,59 @@ |
||||
from django.db import models |
||||
|
||||
|
||||
# Create your models here. |
||||
class TestCinema(models.Model): |
||||
id = models.AutoField(primary_key=True) |
||||
name = models.CharField(max_length=50) |
||||
zz_code = models.CharField(max_length=50) |
||||
db_config = models.TextField() |
||||
user_config = models.TextField() |
||||
is_active = models.BooleanField(default=True) |
||||
|
||||
def __str__(self): |
||||
return self.name |
||||
|
||||
class Meta: |
||||
verbose_name = '测试影院' |
||||
verbose_name_plural = '测试影院' |
||||
db_table = 'ai_show_cinema' |
||||
|
||||
|
||||
class PromptTemplate(models.Model): |
||||
id = models.AutoField(primary_key=True) |
||||
prompt_type = models.CharField(max_length=50) |
||||
prompt_key = models.CharField(max_length=50) |
||||
prompt_val = models.TextField() |
||||
del_flag = models.BooleanField(default=False) |
||||
|
||||
def __str__(self): |
||||
return self.prompt_key |
||||
|
||||
class Meta: |
||||
verbose_name = '提示词' |
||||
verbose_name_plural = '提示词' |
||||
db_table = 'ai_prompt_template' |
||||
|
||||
|
||||
class AiShow(models.Model): |
||||
id = models.AutoField(primary_key=True) |
||||
cinema = models.CharField(max_length=50) |
||||
zz_code = models.CharField(max_length=50) |
||||
show_date = models.DateField() |
||||
is_ai_show = models.BooleanField(default=True) |
||||
show = models.TextField() |
||||
sales = models.CharField(max_length=50) |
||||
prompt = models.TextField() |
||||
result = models.TextField() |
||||
message = models.TextField() |
||||
created_at = models.DateTimeField(auto_now_add=True) |
||||
take_times = models.IntegerField(default=0) |
||||
take_tokens = models.CharField(default='', max_length=2000) |
||||
|
||||
def __str__(self): |
||||
return self.cinema |
||||
|
||||
class Meta: |
||||
verbose_name = 'AI排片数据' |
||||
verbose_name_plural = 'AI排片数据' |
||||
db_table = 'ai_show_result' |
||||
@ -0,0 +1,21 @@ |
||||
from rest_framework import serializers |
||||
|
||||
from ai.models import * |
||||
|
||||
|
||||
class TestCinemaSerializer(serializers.ModelSerializer): |
||||
class Meta: |
||||
model = TestCinema |
||||
fields = '__all__' |
||||
|
||||
|
||||
class PromptTemplateSerializer(serializers.ModelSerializer): |
||||
class Meta: |
||||
model = PromptTemplate |
||||
fields = '__all__' |
||||
|
||||
|
||||
class AiShowSerializer(serializers.ModelSerializer): |
||||
class Meta: |
||||
model = AiShow |
||||
fields = '__all__' |
||||
@ -0,0 +1,10 @@ |
||||
from celery import shared_task |
||||
from ai.utils.show_process import show_main_process |
||||
|
||||
|
||||
|
||||
@shared_task |
||||
def ai_show_general(): |
||||
show_main_process() |
||||
print("task success") |
||||
return True |
||||
@ -0,0 +1,3 @@ |
||||
from django.test import TestCase |
||||
|
||||
# Create your tests here. |
||||
@ -0,0 +1,25 @@ |
||||
""" |
||||
URL configuration for dingxin_toolbox_drf project. |
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see: |
||||
https://docs.djangoproject.com/en/4.2/topics/http/urls/ |
||||
Examples: |
||||
Function views |
||||
1. Add an import: from my_app import views |
||||
2. Add a URL to urlpatterns: path('', views.home, name='home') |
||||
Class-based views |
||||
1. Add an import: from other_app.views import Home |
||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') |
||||
Including another URLconf |
||||
1. Import the include() function: from django.urls import include, path |
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) |
||||
""" |
||||
from django.contrib import admin |
||||
from django.urls import path, include |
||||
from ai.views import * |
||||
|
||||
urlpatterns = [ |
||||
path('manual_general_show', manual_general_show), |
||||
path('get_cinema_show_result', get_cinema_show_result), |
||||
path('clear', clear_lock), |
||||
] |
||||
@ -0,0 +1,37 @@ |
||||
import datetime |
||||
from chinese_calendar import (is_holiday, is_workday) |
||||
|
||||
|
||||
def get_data_datetime(show_date): |
||||
show_date_obj = datetime.datetime.strptime(show_date, '%Y-%m-%d') |
||||
target_start_datetime_obj = show_date_obj + datetime.timedelta(hours=6) |
||||
target_end_datetime_obj = show_date_obj + datetime.timedelta(hours=29, minutes=59, seconds=59) |
||||
data_start_datetime_obj = show_date_obj + datetime.timedelta(days=-7) + datetime.timedelta(hours=6) |
||||
data_end_datetime_obj = show_date_obj + datetime.timedelta(hours=5, minutes=59, seconds=59) |
||||
history_start = datetime.datetime.strftime(data_start_datetime_obj, '%Y-%m-%d %H:%M:%S') |
||||
history_end = datetime.datetime.strftime(data_end_datetime_obj, '%Y-%m-%d %H:%M:%S') |
||||
target_start = datetime.datetime.strftime(target_start_datetime_obj, '%Y-%m-%d %H:%M:%S') |
||||
target_end = datetime.datetime.strftime(target_end_datetime_obj, '%Y-%m-%d %H:%M:%S') |
||||
return history_start, history_end, target_start, target_end |
||||
|
||||
|
||||
def get_date_type(show_date, template_date): |
||||
show_date_obj = datetime.datetime.strptime(show_date, '%Y-%m-%d') |
||||
template_date_obj = datetime.datetime.strptime(template_date, '%Y-%m-%d') |
||||
result = dict() |
||||
# 处理参考数据日期 |
||||
history_date_list = [(show_date_obj - datetime.timedelta(days=i)) for i in range(7, 0, -1)] |
||||
history_date = '、'.join( |
||||
[f'{datetime.date.strftime(d, "%Y-%m-%d")}({"节假日" if is_holiday(d) else "工作日"})' for d in |
||||
history_date_list]) |
||||
# 处理目标日期 |
||||
show_date = f'{datetime.date.strftime(show_date_obj, "%Y-%m-%d")}({"节假日" if is_holiday(show_date_obj) else "工作日"})' |
||||
show_date_is_holiday = is_holiday(show_date_obj) |
||||
# 处理模板日期 |
||||
template_date = f'{datetime.date.strftime(template_date_obj, "%Y-%m-%d")}({"节假日" if is_holiday(template_date_obj) else "工作日"})' |
||||
template_date_is_holiday = is_holiday(template_date_obj) |
||||
return history_date, show_date, show_date_is_holiday, template_date, template_date_is_holiday |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
get_date_type("2026-06-13", "2026-06-01") |
||||
@ -0,0 +1,136 @@ |
||||
import pymysql |
||||
from pymysql.cursors import DictCursor |
||||
from ai.utils.sql import * |
||||
import datetime |
||||
import pandas as pd |
||||
|
||||
|
||||
class GetData: |
||||
def __init__(self, db_config): |
||||
self.conn = pymysql.connect(**db_config) |
||||
self.cur = self.conn.cursor(cursor=DictCursor) |
||||
|
||||
def exit(self): |
||||
try: |
||||
self.cur.close() |
||||
self.conn.close() |
||||
except Exception as e: |
||||
print(e) |
||||
|
||||
# 获取指定日期范围的排片数据 |
||||
def get_show_data(self, start_datetime, end_datetime): |
||||
# print(self.cur.mogrify(GET_SHOW_DATA, (start_datetime, end_datetime))) |
||||
self.cur.execute(GET_SHOW_DATA, (start_datetime, end_datetime)) |
||||
show_data = self.cur.fetchall() |
||||
show_data_mapping = { |
||||
'hall_name': '影厅别名', |
||||
'hall_id': '影厅id', |
||||
'movie_name': '影片别名', |
||||
'movie_id': '本地影片id', |
||||
'language': '语言', |
||||
'show_date': '放映日期', |
||||
'start_time': '开始时间', |
||||
'end_time': '结束时间', |
||||
'length': '片长', |
||||
'duration': '场间', |
||||
} |
||||
return self.format_to_csv(show_data, show_data_mapping) |
||||
|
||||
# 获取指定范围的影片销售数据 |
||||
def get_sell_data(self, start_datetime, end_datetime): |
||||
# print(self.cur.mogrify(GET_SELL_DATA, (start_datetime, end_datetime))) |
||||
self.cur.execute(GET_SELL_DATA, (start_datetime, end_datetime, start_datetime, end_datetime)) |
||||
sell_data = self.cur.fetchall() |
||||
sell_data_mapping = { |
||||
'movie_name': '影片别名', |
||||
'movie_id': '本地影片id', |
||||
'show_date': '放映日期', |
||||
'start_time': '开始时间', |
||||
'hall_name': '影厅别名', |
||||
'hall_id': '影厅id', |
||||
'total_count': '场次观影人数', |
||||
'total_income': '场次收入', |
||||
'seat_num': '影厅座位数', |
||||
'average_price': '平均价', |
||||
'rate': '上座率(单位%)', |
||||
} |
||||
return self.format_to_csv(sell_data, sell_data_mapping) |
||||
|
||||
# 获取指定范围的影片销售数据 |
||||
def get_total_income(self, start_datetime, end_datetime): |
||||
# print(self.cur.mogrify(GET_SELL_DATA, (start_datetime, end_datetime))) |
||||
self.cur.execute(GET_TOTAL_INCOME, (start_datetime, end_datetime, start_datetime, end_datetime)) |
||||
return self.cur.fetchone()['total_income'] |
||||
|
||||
# 获取指定日期的可放映影片 |
||||
def get_available_movie(self, date): |
||||
start_datetime = datetime.datetime.strptime(date, '%Y-%m-%d') + datetime.timedelta(hours=6) |
||||
end_datetime = datetime.datetime.strptime(date, '%Y-%m-%d') + datetime.timedelta(hours=29, minutes=59, |
||||
seconds=59) |
||||
self.cur.execute(GET_AVAILABLE_MOVIE, (start_datetime, end_datetime)) |
||||
available_movie = self.cur.fetchall() |
||||
available_movie_list = [ |
||||
f"\t《{m['cinema_movie_alias']}》 - 影片id:{m['cinema_movie_id']},影片时长:{m['cinema_movie_time']},语言:{m['language']},制式:{m['media_type']}, 最早排片开始时间:{m['cinema_movie_start_datetime']}, 最晚排片截止时间:{m['cinema_movie_end_datetime']};" |
||||
for m in available_movie] |
||||
return '\n'.join(available_movie_list) |
||||
|
||||
# 获取新上映的影片 |
||||
def get_new_movie(self, date): |
||||
start_datetime = datetime.datetime.strptime(date, '%Y-%m-%d') |
||||
end_datetime = datetime.datetime.strptime(date, '%Y-%m-%d') + datetime.timedelta(hours=29, minutes=59, |
||||
seconds=59) |
||||
self.cur.execute(GET_NEW_MOVIE, (start_datetime, end_datetime)) |
||||
new = self.cur.fetchall() |
||||
new_list = [f"《{m['cinema_movie_alias']}》" for m in new] |
||||
return new_list |
||||
|
||||
# 获取影厅支持的制式 |
||||
def get_hall_media_type(self): |
||||
self.cur.execute(GET_HALL_MEDIA_TYPE) |
||||
hall_data = self.cur.fetchall() |
||||
# print(hall_data) |
||||
hall_dict = dict() |
||||
|
||||
# 处理成对应的字典格式 {"影厅别名": {"hall_id":影厅id,"media_type": 影片制式列表}} |
||||
for hall in hall_data: |
||||
if hall['cinema_hall_name'] not in hall_dict.keys(): |
||||
hall_dict[hall['cinema_hall_name']] = { |
||||
'hall_id': hall['cinema_hall_id'], |
||||
'media_type': [hall['media_type'], ] |
||||
} |
||||
else: |
||||
hall_dict[hall['cinema_hall_name']]['media_type'].append(hall['media_type']) |
||||
# 拼装字符串 |
||||
hall_str_list = [] |
||||
for hall, val in hall_dict.items(): |
||||
hall_str_list.append(f"\t{hall} - 影厅id:{val['hall_id']},支持制式:{','.join(val['media_type'])};") |
||||
return '\n'.join(hall_str_list) |
||||
|
||||
# 获取模板日期 |
||||
def get_template_date(self, start_datetime, end_datetime): |
||||
basic_val = 4 |
||||
self.cur.execute(GET_TEMPLATE_DATE, (start_datetime, end_datetime, basic_val)) |
||||
template_date = self.cur.fetchall()[0]['template_date'] |
||||
return template_date |
||||
|
||||
# 数据转csv格式字符串 |
||||
@staticmethod |
||||
def format_to_csv(dict_data, mapping): |
||||
# print(dict_data) |
||||
new_dict = [{mapping[k]: v for k, v in d.items()} for d in dict_data] |
||||
return pd.DataFrame(new_dict).to_csv(index=False) |
||||
|
||||
def get_media_type(self): |
||||
self.cur.execute(GET_HALL_MEDIA_TYPE) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
from main import cinema_list |
||||
|
||||
data = GetData(cinema_list[0]['db']) |
||||
# print(data.get_show_data('2026-05-28 06:00:00', '2026-06-04 05:59:59')) |
||||
# print(data.get_sell_data('2026-05-28 06:00:00', '2026-06-04 05:59:59')) |
||||
# print(data.get_available_movie('2026-06-05')) |
||||
print(data.get_new_movie('2026-06-05')) |
||||
# print(data.get_hall_media_type()) |
||||
# print(data.get_template_date('2026-05-28 06:00:00', '2026-06-04 05:59:59')) |
||||
@ -0,0 +1,54 @@ |
||||
from ai.models import * |
||||
from ai.utils.show_prompt import * |
||||
import datetime |
||||
from django_redis import get_redis_connection |
||||
|
||||
# ai排片主流程 |
||||
def show_main_process(): |
||||
# 查看状态 |
||||
redis_conn = get_redis_connection() |
||||
redis_key = f'ai_show{datetime.date.today().strftime("%Y%m%d")}' |
||||
if redis_conn.exists(redis_key): |
||||
return False |
||||
# 获取影院列表 |
||||
redis_conn.set(redis_key, 1, ex=60*60*20) |
||||
test_cinema_list = TestCinema.objects.filter(is_active=True).all() |
||||
# 生成目标日期 |
||||
show_date = datetime.date.strftime(datetime.date.today() + datetime.timedelta(days=3), '%Y-%m-%d') |
||||
for cinema in test_cinema_list: |
||||
print(cinema.name) |
||||
show_ai = ShowAI(cinema, show_date) |
||||
prompt = show_ai.general_prompt() |
||||
start = datetime.datetime.now() |
||||
result, message, tokens = show_ai.get_show_result_ai() |
||||
end = datetime.datetime.now() |
||||
print('prompt:', prompt) |
||||
print('result:', result) |
||||
print('message:', message) |
||||
print('tokens:', tokens) |
||||
# 获取排片数据 |
||||
_show = next((s for s in result.split('------') if s.startswith('\n影厅别名,影厅id')), '') |
||||
_show = _show.strip() |
||||
print('_show:', _show) |
||||
# 获取销售额 |
||||
_sales = next((s for s in result.split('\n') if s.startswith('预估销售数据')), '').replace('预估销售数据:', '') |
||||
_sales = _sales.replace('约', '').replace('元', '') |
||||
print('_sales:', _sales) |
||||
# 处理返回结果 |
||||
try: |
||||
AiShow.objects.create( |
||||
cinema=cinema.name, |
||||
zz_code=cinema.zz_code, |
||||
show_date=show_date, |
||||
is_ai_show=True, |
||||
show=_show, |
||||
sales=_sales, |
||||
prompt=prompt, |
||||
result=result, |
||||
message=message, |
||||
take_times=int((end - start).seconds), |
||||
take_tokens=tokens |
||||
) |
||||
except Exception as e: |
||||
print(e) |
||||
return True |
||||
@ -0,0 +1,130 @@ |
||||
from django.db.models import Q |
||||
from ai.models import PromptTemplate |
||||
from ai.utils.show_database import GetData |
||||
from ai.utils.datetime_format import (get_data_datetime, get_date_type) |
||||
import datetime |
||||
import random |
||||
import json |
||||
from openai import OpenAI |
||||
|
||||
|
||||
class ShowAI: |
||||
def __init__(self, cinema_info, show_date): |
||||
self.cinema_name = cinema_info.name |
||||
self.cinema_zz_code = cinema_info.zz_code |
||||
self.cinema_db_config = json.loads(cinema_info.db_config) |
||||
self.user_config = json.loads(cinema_info.user_config) |
||||
self.show_date = show_date |
||||
self.prompt = "" |
||||
self.client = OpenAI( |
||||
api_key='sk-b7993bf4c8844e79bf84f08f07ff86d9', |
||||
base_url='https://api.deepseek.com', |
||||
) |
||||
|
||||
# 生成提示词 |
||||
def general_prompt(self): |
||||
data = GetData(self.cinema_db_config) |
||||
# 准备各种日期时间 |
||||
history_start, history_end, target_start, target_end = get_data_datetime(self.show_date) |
||||
temp = datetime.datetime.strftime(data.get_template_date(history_start, history_end), '%Y-%m-%d') |
||||
history_date, target_date, target_date_is_holiday, template_date, template_date_is_holiday = get_date_type( |
||||
self.show_date, temp) |
||||
# print(history_start, history_end, target_start, target_end, history_date, show_date, template_date) |
||||
|
||||
# 开始处理提示词 |
||||
prompt_list = [] |
||||
# 处理排片数据 |
||||
pre_data = PromptTemplate.objects.filter( |
||||
Q(del_flag=False) & Q(prompt_type='show') & Q(prompt_key='PreData')).first().prompt_val # 获取提示词模板 |
||||
pre_data = pre_data.replace('{history_show}', data.get_show_data(history_start, history_end)) # 处理排片数据 |
||||
pre_data = pre_data.replace('{history_sales}', data.get_sell_data(history_start, history_end)) # 处理销售数据 |
||||
pre_data = pre_data.replace('{target_already_show}', |
||||
data.get_show_data(target_start, target_end)) # 处理目标日期已排场次数据 |
||||
pre_data = pre_data.replace('{reference_date}', history_date) # 处理参考日期 |
||||
pre_data = pre_data.replace('{template_date}', template_date) # 处理模板日期 |
||||
pre_data = pre_data.replace('{target_date}', target_date) # 处理目标日期 |
||||
prompt_list.append(pre_data) |
||||
|
||||
# 处理角色说明 |
||||
role = PromptTemplate.objects.filter( |
||||
Q(del_flag=False) & Q(prompt_type='show') & Q(prompt_key='Role')).first().prompt_val # 获取提示词模板 |
||||
role = role.replace('{template_date}', template_date) |
||||
prompt_list.append(role) |
||||
|
||||
# 处理影片和影厅信息 |
||||
movie_hall = PromptTemplate.objects.filter( |
||||
Q(del_flag=False) & Q(prompt_type='show') & Q(prompt_key='MovieHall')).first().prompt_val # 获取提示词模板 |
||||
movie_hall = movie_hall.replace('{available_movie}', data.get_available_movie(self.show_date)) # 处理可排影片 |
||||
movie_hall = movie_hall.replace('{hall_info}', data.get_hall_media_type()) # 处理影厅信息 |
||||
free_hall = self.user_config['holiday_date_free_hall'] if target_date_is_holiday else self.user_config[ |
||||
'holiday_date_free_hall'] |
||||
movie_hall = movie_hall.replace('{free_hall}', |
||||
'\t无' if len(free_hall) == 0 else '\n'.join( |
||||
f'\t{h};' for h in free_hall)) # 处理不可排片影厅 |
||||
prompt_list.append(movie_hall) |
||||
|
||||
# 处理具体要求 |
||||
rules = PromptTemplate.objects.filter( |
||||
Q(del_flag=False) & Q(prompt_type='show') & Q(prompt_key='Rules')).first().prompt_val # 获取提示词模板 |
||||
rules = rules.replace('{template_date}', template_date) # 处理模板日期 |
||||
# 获取新片 |
||||
new_movie_str_list = [] |
||||
new_movie = data.get_new_movie(self.show_date) |
||||
for new in new_movie: |
||||
new_movie_str_list.append( |
||||
f"\t增加{new}的场次,建议排{str(random.randint(2, 4))}场,可根据影片热度和口碑适当增加;") |
||||
rules = rules.replace('{new_movie}', |
||||
'\t无新片上映' if len(new_movie_str_list) == 0 else '\n'.join(new_movie_str_list)) # 处理新片数据 |
||||
prompt_list.append(rules) |
||||
|
||||
# 处理基本规则 |
||||
basic = PromptTemplate.objects.filter( |
||||
Q(del_flag=False) & Q(prompt_type='show') & Q(prompt_key='Basic')).first().prompt_val # 获取提示词模板 |
||||
start = self.user_config['holiday_date_start'] if target_date_is_holiday else self.user_config[ |
||||
'work_date_start'] |
||||
end = self.user_config['holiday_date_end'] if target_date_is_holiday else self.user_config['work_date_end'] |
||||
basic = basic.replace('{start}', start) |
||||
basic = basic.replace('{end}', end) |
||||
prompt_list.append(basic) |
||||
|
||||
# 处理增减场次规则 |
||||
add_reduce = PromptTemplate.objects.filter( |
||||
Q(del_flag=False) & Q(prompt_type='show') & Q(prompt_key='AddReduce')).first().prompt_val # 获取提示词模板 |
||||
prompt_list.append(add_reduce) |
||||
|
||||
# 处理黄金时段 |
||||
prime_time = PromptTemplate.objects.filter( |
||||
Q(del_flag=False) & Q(prompt_type='show') & Q(prompt_key='PrimeTime')).first().prompt_val # 获取提示词模板 |
||||
prompt_list.append(prime_time) |
||||
|
||||
# 处理输出目标 |
||||
output = PromptTemplate.objects.filter( |
||||
Q(del_flag=False) & Q(prompt_type='show') & Q(prompt_key='Output')).first().prompt_val # 获取提示词模板 |
||||
prompt_list.append(output) |
||||
|
||||
# 打印提示词 |
||||
self.prompt = '\n'.join(prompt_list) |
||||
print(self.prompt) |
||||
# 关闭数据库连接 |
||||
data.exit() |
||||
return self.prompt |
||||
|
||||
# 请求AI |
||||
def get_show_result_ai(self): |
||||
# 生成提示词 |
||||
# self.general_prompt() |
||||
# 与DeepSeek开始对话 |
||||
print("与DeepSeek开始对话") |
||||
response = self.client.chat.completions.create( |
||||
model='deepseek-v4-pro', |
||||
messages=[ |
||||
{'role': 'system', 'content': 'You are a helpful assistant'}, |
||||
{'role': 'user', 'content': self.prompt}, |
||||
], |
||||
stream=False, |
||||
reasoning_effort="high", |
||||
extra_body={"thinking": {"type": "enabled"}} |
||||
) |
||||
# print(dict(response)) |
||||
# print(response.choices[0].message.content) |
||||
return response.choices[0].message.content, response.model_dump_json(), response.usage.model_dump_json() |
||||
@ -0,0 +1,182 @@ |
||||
# 排片数据 |
||||
GET_SHOW_DATA = """ |
||||
SELECT hi.cinema_hall_name as hall_name, |
||||
hi.cinema_hall_id as hall_id, |
||||
mi.cinema_movie_alias as movie_name, |
||||
mi.cinema_movie_id as movie_id, |
||||
mlt.cinema_movie_lang_type_desc as language, |
||||
DATE_FORMAT(ms.cinema_movie_show_start_time, '%%Y-%%m-%%d') as show_date, |
||||
DATE_FORMAT(ms.cinema_movie_show_start_time, '%%H:%%i') as start_time, |
||||
DATE_FORMAT(ms.cinema_movie_show_end_time, '%%H:%%i') as end_time, |
||||
CAST(TIME_TO_SEC(TIMEDIFF(ms.cinema_movie_show_end_time, ms.cinema_movie_show_start_time)) / |
||||
60 AS UNSIGNED) as length, |
||||
IFNULL(MINUTE(TIMEDIFF(ms.cinema_movie_show_start_time, (SELECT MAX(cinema_movie_show_end_time) |
||||
FROM cinema_movie_show t |
||||
WHERE t.cinema_hall_id = ms.cinema_hall_id |
||||
AND t.cinema_movie_show_start_date = ms.cinema_movie_show_start_date |
||||
AND t.cinema_del_flag = 1 |
||||
AND ms.cinema_movie_show_start_time >= t.cinema_movie_show_end_time))), |
||||
0) as duration |
||||
FROM cinema_movie_show ms |
||||
LEFT JOIN cinema_hall_info hi ON ms.cinema_hall_id = hi.cinema_hall_id |
||||
LEFT JOIN cinema_movie_info mi ON ms.cinema_movie_id = mi.cinema_movie_id |
||||
LEFT JOIN cinema_movie_lang_type mlt ON mi.cinema_movie_lang_id = mlt.cinema_movie_lang_type_id |
||||
WHERE ms.cinema_del_flag = 1 |
||||
AND ms.cinema_movie_show_start_time >= %s |
||||
AND ms.cinema_movie_show_start_time <= %s |
||||
ORDER BY show_date, hall_id, start_time; |
||||
""" |
||||
|
||||
# 获取销售数据 |
||||
GET_SELL_DATA = """ |
||||
SELECT md.movie_name, |
||||
md.movie_id, |
||||
md.show_date, |
||||
md.start_time, |
||||
md.hall_name, |
||||
md.hall_id, |
||||
SUM(md.count) as total_count, |
||||
SUM(md.income) as total_income, |
||||
md.seat_num, |
||||
ROUND(IF(SUM(md.income) = 0, 0.0, SUM(md.income) / SUM(md.count)), 2) as average_price, |
||||
ROUND(SUM(md.count) / md.seat_num * 100, 2) as rate |
||||
FROM ( |
||||
-- 售票 |
||||
SELECT ms.cinema_movie_show_id as cinema_movie_show_id, |
||||
mi.cinema_movie_alias as movie_name, |
||||
mi.cinema_movie_id as movie_id, |
||||
DATE_FORMAT(ms.cinema_movie_show_start_time, '%%Y-%%m-%%d') as show_date, |
||||
CAST(TIME(ms.cinema_movie_show_start_time) AS CHAR) as start_time, |
||||
hi.cinema_hall_name as hall_name, |
||||
hi.cinema_hall_id as hall_id, |
||||
SUM(IF(sl.cinema_ticket_status <> 3, 1, 0)) as count, |
||||
SUM(IF(sl.cinema_ticket_status <> 3, sl.cinema_ticket_income, 0)) as income, |
||||
ms.cinema_hall_seat_num as seat_num |
||||
FROM cinema_movie_show ms |
||||
LEFT JOIN cinema_sell_log sl ON ms.cinema_movie_show_id = sl.cinema_movie_show_id |
||||
JOIN cinema_movie_info mi ON ms.cinema_movie_id = mi.cinema_movie_id |
||||
JOIN cinema_hall_info hi ON ms.cinema_hall_id = hi.cinema_hall_id |
||||
WHERE ms.cinema_movie_show_joinflg = 0 |
||||
AND ms.cinema_movie_show_start_time >= %s |
||||
AND ms.cinema_movie_show_start_time <= %s |
||||
AND ms.cinema_del_flag = 1 |
||||
AND NOT (ms.cinema_movie_show_sold_num = 0 AND ms.cinema_movie_show_status <> 1) |
||||
GROUP BY ms.cinema_movie_show_id, CAST(ms.cinema_movie_show_id AS CHAR) |
||||
UNION |
||||
-- 补登 |
||||
SELECT ms.cinema_movie_show_id as cinema_movie_show_id, |
||||
mi.cinema_movie_alias as movie_name, |
||||
mi.cinema_movie_id as movie_id, |
||||
DATE_FORMAT(ms.cinema_movie_show_start_time, '%%Y-%%m-%%d') as show_date, |
||||
CAST(TIME(ms.cinema_movie_show_start_time) AS CHAR) as start_time, |
||||
hi.cinema_hall_name as hall_name, |
||||
hi.cinema_hall_id as hall_id, |
||||
SUM(sa.cinema_sell_add_num) as count, |
||||
SUM(sa.cinema_sell_add_total) as income, |
||||
ms.cinema_hall_seat_num as seat_num |
||||
FROM cinema_sell_add sa |
||||
LEFT JOIN cinema_movie_show ms ON sa.cinema_sell_add_showid = ms.cinema_movie_show_id |
||||
LEFT JOIN cinema_hall_info hall ON ms.cinema_hall_id = hall.cinema_hall_id |
||||
LEFT JOIN cinema_show_policy_map spm ON sa.cinema_sell_add_showid = spm.cinema_movie_show_id AND |
||||
sa.cinema_sell_add_policy = spm.cinema_show_policy_map_id |
||||
JOIN cinema_hall_info hi ON ms.cinema_hall_id = hi.cinema_hall_id |
||||
JOIN cinema_movie_info mi ON ms.cinema_movie_id = mi.cinema_movie_id |
||||
WHERE ms.cinema_movie_show_joinflg = 0 |
||||
AND ms.cinema_movie_show_start_time >= %s |
||||
AND ms.cinema_movie_show_start_time <= %s |
||||
AND ms.cinema_del_flag = 1 |
||||
AND NOT (ms.cinema_movie_show_sold_num = 0 AND ms.cinema_movie_show_status <> 1) |
||||
GROUP BY ms.cinema_movie_show_id, CAST(ms.cinema_movie_show_id AS CHAR)) as md |
||||
GROUP BY md.cinema_movie_show_id, CAST(md.cinema_movie_show_id AS CHAR) |
||||
ORDER BY md.show_date, md.hall_id, md.start_time; |
||||
""" |
||||
|
||||
# 获取指定日期的可放映影片 |
||||
GET_AVAILABLE_MOVIE = """ |
||||
SELECT cmi.cinema_movie_alias, |
||||
cmi.cinema_movie_id, |
||||
cmi.cinema_movie_time, |
||||
cmlt.cinema_movie_lang_type_desc as language, |
||||
scvm.system_const_val_desc as media_type, |
||||
cmi.cinema_movie_start_datetime, |
||||
cmi.cinema_movie_end_datetime |
||||
FROM cinema_movie_info cmi |
||||
JOIN cinema_movie_lang_type cmlt ON cmi.cinema_movie_lang_id = cmlt.cinema_movie_lang_type_id |
||||
JOIN system_const_val_map scvm ON cmi.cinema_movie_media_type = scvm.system_const_val_value |
||||
WHERE scvm.system_const_sub_module = 'new_media_type' |
||||
AND cmi.cinema_movie_start_datetime <= %s |
||||
AND cmi.cinema_movie_end_datetime > %s; |
||||
""" |
||||
|
||||
# 获取新上映的影片 |
||||
GET_NEW_MOVIE = """SELECT cmi.cinema_movie_alias, |
||||
cmi.cinema_movie_id, |
||||
cmi.cinema_movie_time, |
||||
cmlt.cinema_movie_lang_type_desc as language, |
||||
scvm.system_const_val_desc as media_type, |
||||
cmi.cinema_movie_start_datetime, |
||||
cmi.cinema_movie_end_datetime |
||||
FROM cinema_movie_info cmi |
||||
JOIN cinema_movie_lang_type cmlt ON cmi.cinema_movie_lang_id = cmlt.cinema_movie_lang_type_id |
||||
JOIN system_const_val_map scvm ON cmi.cinema_movie_media_type = scvm.system_const_val_value |
||||
WHERE scvm.system_const_sub_module = 'new_media_type' |
||||
AND cmi.cinema_movie_start_datetime >= %s |
||||
AND cmi.cinema_movie_start_datetime <= %s;""" |
||||
|
||||
# 获取影厅支持的制式 |
||||
GET_HALL_MEDIA_TYPE = """ |
||||
SELECT chi.cinema_hall_name, cms.cinema_hall_id, scvm.system_const_val_desc as media_type |
||||
FROM cinema_movie_show cms |
||||
JOIN cinema_movie_info cmi ON cms.cinema_movie_id = cmi.cinema_movie_id |
||||
JOIN cinema_hall_info chi ON cms.cinema_hall_id = chi.cinema_hall_id |
||||
JOIN system_const_val_map scvm ON cmi.cinema_movie_media_type = scvm.system_const_val_value |
||||
WHERE scvm.system_const_sub_module = 'new_media_type' |
||||
AND chi.cinema_delete_flag = 0 |
||||
GROUP BY chi.cinema_hall_id, media_type; |
||||
""" |
||||
|
||||
# 获取模板日期 |
||||
GET_TEMPLATE_DATE = """ |
||||
SELECT cms.cinema_movie_show_start_date as template_date, COUNT(cinema_movie_show_id) as show_count |
||||
FROM cinema_movie_show cms |
||||
WHERE cms.cinema_del_flag = 1 |
||||
AND cms.cinema_movie_show_start_time >= %s |
||||
AND cms.cinema_movie_show_start_time <= %s |
||||
GROUP BY cms.cinema_movie_show_start_date |
||||
HAVING show_count > (SELECT COUNT(chi.cinema_hall_id) FROM cinema_hall_info chi WHERE chi.cinema_delete_flag = 0) * %s |
||||
ORDER BY template_date DESC |
||||
LIMIT 1; |
||||
""" |
||||
|
||||
|
||||
# 获取目标日期的销售总额 |
||||
GET_TOTAL_INCOME = """ |
||||
SELECT SUM(md.income) as total_income |
||||
FROM ( |
||||
-- 售票 |
||||
SELECT SUM(IF(sl.cinema_ticket_status <> 3, sl.cinema_ticket_income, 0)) as income |
||||
FROM cinema_movie_show ms |
||||
LEFT JOIN cinema_sell_log sl ON ms.cinema_movie_show_id = sl.cinema_movie_show_id |
||||
JOIN cinema_movie_info mi ON ms.cinema_movie_id = mi.cinema_movie_id |
||||
JOIN cinema_hall_info hi ON ms.cinema_hall_id = hi.cinema_hall_id |
||||
WHERE ms.cinema_movie_show_joinflg = 0 |
||||
AND ms.cinema_movie_show_start_time >= %s |
||||
AND ms.cinema_movie_show_start_time <= %s |
||||
AND ms.cinema_del_flag = 1 |
||||
AND NOT (ms.cinema_movie_show_sold_num = 0 AND ms.cinema_movie_show_status <> 1) |
||||
UNION |
||||
-- 补登 |
||||
SELECT SUM(sa.cinema_sell_add_total) as income |
||||
FROM cinema_sell_add sa |
||||
LEFT JOIN cinema_movie_show ms ON sa.cinema_sell_add_showid = ms.cinema_movie_show_id |
||||
LEFT JOIN cinema_hall_info hall ON ms.cinema_hall_id = hall.cinema_hall_id |
||||
LEFT JOIN cinema_show_policy_map spm ON sa.cinema_sell_add_showid = spm.cinema_movie_show_id AND |
||||
sa.cinema_sell_add_policy = spm.cinema_show_policy_map_id |
||||
JOIN cinema_hall_info hi ON ms.cinema_hall_id = hi.cinema_hall_id |
||||
JOIN cinema_movie_info mi ON ms.cinema_movie_id = mi.cinema_movie_id |
||||
WHERE ms.cinema_movie_show_joinflg = 0 |
||||
AND ms.cinema_movie_show_start_time >= %s |
||||
AND ms.cinema_movie_show_start_time <= %s |
||||
AND ms.cinema_del_flag = 1 |
||||
AND NOT (ms.cinema_movie_show_sold_num = 0 AND ms.cinema_movie_show_status <> 1)) md |
||||
""" |
||||
@ -0,0 +1,75 @@ |
||||
from django.http import JsonResponse |
||||
from django.views.decorators.csrf import csrf_exempt |
||||
from ai.models import * |
||||
import datetime |
||||
import json |
||||
from ai.utils.show_database import GetData |
||||
from ai.utils.show_process import show_main_process |
||||
from django_redis import get_redis_connection |
||||
|
||||
|
||||
# Create your views here. |
||||
|
||||
|
||||
# 手动触发ai排片 |
||||
@csrf_exempt |
||||
def manual_general_show(request): |
||||
result = show_main_process() |
||||
result_dict = { |
||||
'status': 'success' if result else 'fail', |
||||
'message': '生成成功' if result else '生成失败', |
||||
} |
||||
return JsonResponse(result_dict, json_dumps_params={'ensure_ascii': False}) |
||||
|
||||
|
||||
# 更新指定日期的排片 |
||||
@csrf_exempt |
||||
def get_cinema_show_result(request): |
||||
zz_code = request.GET.dict().get('cinema_code') |
||||
show_date = request.GET.dict().get('show_date') |
||||
print(zz_code, show_date) |
||||
cinema = TestCinema.objects.filter(zz_code=zz_code).first() |
||||
start = datetime.datetime.strftime(datetime.datetime.strptime(show_date, '%Y-%m-%d') + datetime.timedelta(hours=6), |
||||
'%Y-%m-%d %H:%M:%S') |
||||
end = datetime.datetime.strftime( |
||||
datetime.datetime.strptime(show_date, '%Y-%m-%d') + datetime.timedelta(hours=29, minutes=59, seconds=59), |
||||
'%Y-%m-%d %H:%M:%S') |
||||
if cinema: |
||||
data = GetData(json.loads(cinema.db_config)) |
||||
show = data.get_show_data(start, end) |
||||
income = data.get_total_income(start, end) |
||||
try: |
||||
AiShow.objects.create( |
||||
cinema=cinema.name, |
||||
zz_code=cinema.zz_code, |
||||
show_date=show_date, |
||||
is_ai_show=False, |
||||
show=show, |
||||
sales=income, |
||||
prompt='', |
||||
result='', |
||||
message='', |
||||
take_time=0, |
||||
take_tokens='0' |
||||
) |
||||
except Exception as e: |
||||
print(e) |
||||
result_dict = { |
||||
'status': 'success', |
||||
'message': '生成成功', |
||||
} |
||||
return JsonResponse(result_dict, json_dumps_params={'ensure_ascii': False}) |
||||
|
||||
|
||||
# 清除redis锁 |
||||
@csrf_exempt |
||||
def clear_lock(request): |
||||
redis_conn = get_redis_connection() |
||||
redis_key = f'ai_show{datetime.date.today().strftime("%Y%m%d")}' |
||||
if redis_conn.exists(redis_key): |
||||
redis_conn.delete(redis_key) |
||||
result_dict = { |
||||
'status': 'success', |
||||
'message': '完成', |
||||
} |
||||
return JsonResponse(result_dict, json_dumps_params={'ensure_ascii': False}) |
||||
Binary file not shown.
@ -0,0 +1,18 @@ |
||||
# Generated by Django 4.2.7 on 2026-05-15 03:15 |
||||
|
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('update', '0033_alter_clientrelease_md5'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AddField( |
||||
model_name='cinema', |
||||
name='url', |
||||
field=models.CharField(default=models.CharField(help_text='影院ip', max_length=20, verbose_name='影院ip'), help_text='影院url', max_length=50, verbose_name='影院url'), |
||||
), |
||||
] |
||||
Loading…
Reference in new issue