diff --git a/ai/migrations/0024_aishow_is_manual_test.py b/ai/migrations/0024_aishow_is_manual_test.py new file mode 100644 index 0000000..d29f1b1 --- /dev/null +++ b/ai/migrations/0024_aishow_is_manual_test.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2026-07-13 02:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ai', '0023_movieguidance'), + ] + + operations = [ + migrations.AddField( + model_name='aishow', + name='is_manual_test', + field=models.BooleanField(default=False), + ), + ] diff --git a/ai/models.py b/ai/models.py index f888955..eb33c20 100644 --- a/ai/models.py +++ b/ai/models.py @@ -58,6 +58,7 @@ class AiShow(models.Model): zz_code = models.CharField(max_length=50) show_date = models.DateField() # 排片目标日期 is_ai_show = models.BooleanField(default=True) # 当is_ai_show为True时,记录为ai生成的排片,否则为影院真实排片 + is_manual_test = models.BooleanField(default=False) # 为手动提交的提示词提供标记 ai_model = models.CharField(default='', max_length=100) # ai生成排片时使用的模型 template = models.TextField(default='') # ai生成排片时的模板日期排片数据,csv格式 temp_date = models.CharField(max_length=50, default='') # 模板数据日期 diff --git a/ai/urls.py b/ai/urls.py index eff10f0..59818d8 100644 --- a/ai/urls.py +++ b/ai/urls.py @@ -24,5 +24,7 @@ urlpatterns = [ path('clear', clear_lock), path('report', report), path('report_date', get_report_date_api), - path('new_movie', insert_new_movie) + path('new_movie', insert_new_movie), + path('test', manual_test), + path('test_date', get_test_date), ] diff --git a/ai/utils/manual_utils.py b/ai/utils/manual_utils.py index b368912..32bd68c 100644 --- a/ai/utils/manual_utils.py +++ b/ai/utils/manual_utils.py @@ -1,5 +1,7 @@ import csv from io import StringIO +import pymysql +from pymysql.cursors import DictCursor s = """ 影厅别名,影厅id,影片别名,本地影片id,语言,放映日期,开始时间,结束时间,片长,场间 @@ -59,10 +61,28 @@ s = """ # 将csv转化成字典 def csv_to_obj(csv_data): f = StringIO(csv_data) + print(csv_data, f) reader = csv.DictReader(f) return list(reader) +def get_real_data(cinema_code: str, show_date: str): + db_config = { + 'host': '172.16.1.63', + 'port': 3306, + 'user': 'root', + 'password': 'Cine123456', + 'database': 'dingxin_toolbox', + } + db_conn = pymysql.connect(**db_config) + db_cursor = db_conn.cursor(cursor=DictCursor) + db_cursor.execute( + "SELECT * FROM dingxin_toolbox.ai_show_result WHERE zz_code=%s AND show_date=%s AND is_ai_show=%s", + (cinema_code, show_date, 0)) + real_data = db_cursor.fetchone() + return real_data['show'] + + def count_data(data): count = len(data) - 1 movie_dict = {} @@ -75,8 +95,40 @@ def count_data(data): movie_dict = dict(sorted(movie_dict.items(), key=lambda item: item[1], reverse=True)) print(f"共{count}场") for key, value in movie_dict.items(): - print(f"《{key}》: {value}场 占比{round(value/count*100,2)}%") + print(f"《{key}》: {value}场 占比{round(value / count * 100, 2)}%") + + +def _get_hall_count(show: list) -> dict: + hall_show_count = dict() + for show in show[1:]: + hall = show[None][1] + if hall in hall_show_count.keys(): + hall_show_count[show[None][1]] += 1 + else: + hall_show_count[show[None][1]] = 1 + return hall_show_count + + +def get_hall_show_count(ai: list, real: list) -> dict: + ai_hall_show_count = _get_hall_count(ai) + real_hall_show_count = _get_hall_count(real) + more = ai_hall_show_count if len(ai_hall_show_count) >= len(real_hall_show_count) else real_hall_show_count + hall_show_count = dict() + for key in more.keys(): + hall_show_count[key] = ai_hall_show_count[key] if ai_hall_show_count.get(key, 0) >= real_hall_show_count.get( + key, 0) else real_hall_show_count[key] + return hall_show_count + + +def show_data(zz_code: str, show_date: str): + real_obj = csv_to_obj(get_real_data(zz_code, show_date)) + ai_obj = csv_to_obj(s) + print('ai_obj', ai_obj) + print('real_obj', real_obj) + hall_show_count = get_hall_show_count(ai_obj, real_obj) + print(hall_show_count) if __name__ == '__main__': count_data(csv_to_obj(s)) + # show_data('33040301', '2026-07-13') diff --git a/ai/utils/show_func.py b/ai/utils/show_func.py index 9f66574..eb01b58 100644 --- a/ai/utils/show_func.py +++ b/ai/utils/show_func.py @@ -206,3 +206,9 @@ def get_movie_guidance(cinema, show_date): movie_list.append(f"\t《{m.movie_name}》强制排片占比为{m.guidance}%;") return '\n'.join(movie_list) return '\t无' + + +def get_test_date_from_db(cinema_code: str, show_date: str) -> list: + test_data = AiShow.objects.filter( + Q(zz_code=cinema_code) & Q(show_date=show_date) & Q(is_ai_show=True) & Q(is_manual_test=True)).all() + return [test.prompt_version for test in test_data] diff --git a/ai/utils/show_process.py b/ai/utils/show_process.py index 6523157..24708fc 100644 --- a/ai/utils/show_process.py +++ b/ai/utils/show_process.py @@ -6,6 +6,7 @@ from ai.utils.basic_func import * import datetime from django_redis import get_redis_connection from django.db.models import Q +from ai.models import TestCinema import re @@ -53,7 +54,7 @@ def show_main_process(zz_code=None, day_delta=None): # 获取排片数据 print('result:', result) - if model.config_name in ['lmstudio_qwen3.6_35b','company_qwen3.5_35b']: + if model.config_name in ['lmstudio_qwen3.6_35b', 'company_qwen3.5_35b']: result_obj = json.loads(result.replace('```json', '').replace('}\n```', '}').strip()) else: result_obj = json.loads(result.strip()) @@ -71,6 +72,7 @@ def show_main_process(zz_code=None, day_delta=None): zz_code=cinema.zz_code, show_date=show_date, is_ai_show=True, + is_manual_test=False, ai_model=model.config_name, template=template_show, temp_date=template_date, @@ -88,6 +90,65 @@ def show_main_process(zz_code=None, day_delta=None): print(e) return True + +def show_manual_process(zz_code: str, show_date: str, prompt: str): + cinema = TestCinema.objects.filter(zz_code=zz_code).first() + ai = ShowAI(cinema, show_date) + + start = datetime.datetime.now() # 开始计时 + result, message, tokens = ai.get_show_result_ai(prompt) + end = datetime.datetime.now() # 结束计时 + print('prompt:', prompt) + print('result:', result) + print('message:', message) + print('tokens:', tokens) + + # 获取排片数据 + print('result:', result) + # 获取当前模型 + model = AiModel.objects.filter(current_used=True).first() + if model.config_name in ['lmstudio_qwen3.6_35b', 'company_qwen3.5_35b']: + result_obj = json.loads(result.replace('```json', '').replace('}\n```', '}').strip()) + else: + result_obj = json.loads(result.strip()) + + # 预测排片数据 + _show = result_obj['show'].replace('```', '').replace('csv', '').strip() + + # 预测销售数据 + _sales = str(result_obj['income']).strip() + + ai_data = AiShow.objects.filter(Q(is_ai_show=True) & + Q(is_manual_test=False) & + Q(zz_code=zz_code) & + Q(show_date=show_date)).order_by('-id').first() + print(ai_data) + # 处理返回结果 + try: + AiShow.objects.create( + cinema=cinema.name, + zz_code=cinema.zz_code, + show_date=show_date, + is_ai_show=True, + is_manual_test=True, + ai_model=model.config_name, + template=ai_data.template if ai_data is not None else '', + temp_date=ai_data.temp_date if ai_data is not None else '', + target=ai_data.target if ai_data is not None else '', + show=data_cleansing(_show), + sales=_sales, + prompt=prompt, + result=result, + message=message, + take_times=int((end - start).seconds), + take_tokens=tokens, + prompt_version=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), + ) + except Exception as e: + print(e) + return e + return result + # # 方式一 # _show = next((s for s in result.split('------') if s.startswith('\n影厅别名,影厅id')), '') # _show = _show.strip() diff --git a/ai/utils/show_prompt.py b/ai/utils/show_prompt.py index 0f04a36..20f3e88 100644 --- a/ai/utils/show_prompt.py +++ b/ai/utils/show_prompt.py @@ -238,7 +238,7 @@ class ShowAI: return self.prompt # 请求AI - def get_show_result_ai(self): + def get_show_result_ai(self, prompt=None): # 生成提示词 # self.general_prompt() # 与AI开始对话 @@ -247,7 +247,7 @@ class ShowAI: model=self.ai_model_name, messages=[ {'role': 'system', 'content': '你是中文AI助手。要求:1.所有思考过程必须使用中文。2.所有tool reasoning必须使用中文。3.所有规划必须使用中文。4.即使用户使用英文提问,也必须中文推理。5.最终输出使用中文。'}, - {'role': 'user', 'content': self.prompt}, + {'role': 'user', 'content': self.prompt if prompt is None else prompt} , ], stream=False, reasoning_effort="high", diff --git a/ai/views.py b/ai/views.py index fb94809..9cf0fcb 100644 --- a/ai/views.py +++ b/ai/views.py @@ -3,7 +3,7 @@ from django.db.models import Q from django.views.decorators.csrf import csrf_exempt import json from ai.models import * -from ai.utils.show_process import show_main_process +from ai.utils.show_process import show_main_process, show_manual_process from ai.utils.show_func import * from ai.utils.basic_func import * @@ -53,8 +53,9 @@ def report(request): zz_code = request.GET.dict().get('cinema_code') show_date = request.GET.dict().get('show_date') force = request.GET.dict().get('force') - print(zz_code, show_date) - cinema = TestCinema.objects.filter(zz_code=zz_code).first() + test = request.GET.dict().get('test', None) + print('report-request_params', zz_code, show_date, force, test) + # cinema = TestCinema.objects.filter(zz_code=zz_code).first() # 获取真实排片和销售数据 check_point = datetime.datetime.strftime( datetime.datetime.strptime(show_date, '%Y-%m-%d') + datetime.timedelta(hours=30), '%Y-%m-%d %H:%M:%S') @@ -65,9 +66,18 @@ def report(request): if (not last_real_data) or (force == '1'): get_cinema_show_result_func(zz_code, show_date) - last_ai_data = AiShow.objects.filter(Q(is_ai_show=True) & - Q(zz_code=zz_code) & - Q(show_date=show_date)).order_by('-id').first() + if test is None: + last_ai_data = AiShow.objects.filter(Q(is_ai_show=True) & + Q(is_manual_test=False) & + Q(zz_code=zz_code) & + Q(show_date=show_date)).order_by('-id').first() + else: + last_ai_data = AiShow.objects.filter(Q(is_ai_show=True) & + Q(is_manual_test=True) & + Q(zz_code=zz_code) & + Q(show_date=show_date) & + Q(prompt_version=test)).order_by('-id').first() + print('last_ai_data.pk',last_ai_data.pk) if not last_ai_data: result_dict = { 'status': 'Failure', @@ -164,3 +174,35 @@ def insert_new_movie(request): } print(result_dict) return JsonResponse(result_dict, json_dumps_params={'ensure_ascii': False}) + + +@csrf_exempt +def manual_test(request): + print(request) + cinema_code = request.POST.get('cinema_code') + show_date = request.POST.get('show_date') + prompt = request.POST.get('prompt') + print(cinema_code, show_date, prompt) + + result = show_manual_process(cinema_code, show_date, prompt) + + result_dict = { + 'status': 'success', + 'message': '成功', + 'data': result + } + print(result_dict) + return JsonResponse(result_dict, json_dumps_params={'ensure_ascii': False}) + + +@csrf_exempt +def get_test_date(request): + cinema_code = request.GET.get('cinema_code') + show_date = request.GET.get('show_date') + result_dict = { + 'status': 'success', + 'message': '成功', + 'date': get_test_date_from_db(cinema_code, show_date) + } + print(result_dict) + return JsonResponse(result_dict, json_dumps_params={'ensure_ascii': False})