From 570bafbe47dea543a740c65c9be0427a6a3b27ac Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Mon, 16 Feb 2026 02:19:22 +0000 Subject: [PATCH] =?UTF-8?q?STUDIO=20AI=20AUTOM=C3=81TICO=20,=20iniciar=20u?= =?UTF-8?q?ma=20Super=20Produ=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/__pycache__/models.cpython-311.pyc | Bin 8148 -> 8497 bytes core/__pycache__/pexels.cpython-311.pyc | Bin 0 -> 2526 bytes core/__pycache__/urls.cpython-311.pyc | Bin 935 -> 1134 bytes core/__pycache__/views.cpython-311.pyc | Bin 9974 -> 12558 bytes ...ation_project_estimated_budget_and_more.py | 33 +++ ..._estimated_budget_and_more.cpython-311.pyc | Bin 0 -> 1373 bytes core/models.py | 8 +- core/pexels.py | 42 ++++ core/templates/base.html | 48 +++- core/templates/core/production_library.html | 90 +++++++ core/templates/core/watch_production.html | 223 ++++++++++++++++++ core/urls.py | 4 +- core/views.py | 71 ++++-- requirements.txt | 1 + 14 files changed, 498 insertions(+), 22 deletions(-) create mode 100644 core/__pycache__/pexels.cpython-311.pyc create mode 100644 core/migrations/0005_project_duration_project_estimated_budget_and_more.py create mode 100644 core/migrations/__pycache__/0005_project_duration_project_estimated_budget_and_more.cpython-311.pyc create mode 100644 core/pexels.py create mode 100644 core/templates/core/production_library.html create mode 100644 core/templates/core/watch_production.html diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 8c4b496ac9f5cd6b89363a8844a3fad2ff3e7b39..3efa90c6705dbb1a484aad29893a383745d6e551 100644 GIT binary patch delta 1172 zcmZ{jT}%^M6vyu!oVFCEGcC}eAC$79YhzFfXkyZ4l{FNj&Ei@y)(-;Su@?J*(-sut z+C-ww2BY!37~}4vvXMVuDFpM3D4B=dmX2Ol^3gob_d!F!6vq{KU!U(THWnKSqN zZ^rm(W!UyqlB|R;`;7<5TWu@0^P=DvDjD$+y(th)oHn6|i&>e-I+mSJnh1Hu@68og z8>-AqU2c6M@EU%9sp)K}>ExYUTROQ)yHMSbPMmS_aj<3=Ebo{UvTi<0LJFvK)*ko%v7#f`~nTbBkOBASV^?(pmZ4S zwg%jXcvTK(E|N95ZE?P8ap@iWG0+9o)}VcuhqdMtsX}5Tsil}628Z-#Z%xs1`DA)B zud#`#0!wK5nn|C`Co_qfg%vQ$W}qzXp${u>rFMGML^^lfpEcAU%Y!f2t4LLit*S9Y zja9d`uSs2{aYO1_a+FV1rSPg0Hl%QIWKHfa%^Gs|(m*-(@<3INuF6qEjuuDZqwTC< zqA(`^GpaRB*H4S@k+5cFUbZ$^Eej+(Dzl1Ml z!kltVyv+L^ga4K7Gz(XpE*P+fOevnz(K;90wcF?~@YueaI^dOk@68aGYVBj$Tr!`W z)sAHHT0+w|ZL7cKtG|jki5SOnX*QWFOr|Dg^lW-2Uu)*3CbWryp3<{e<3gwiJQKYg zG4&OPd60X}QLJBZ*^yD#6#spbq4<}6F6XOCXjKUrN~m}Q-Z&z3s?yVTU7!s9=y>2u zW0!``^-uoJg=vU7H;0}v;Z%I!|C|SD8g{8M{}oL1B6LJu$I)urGLvad&%tB0r!S7u zS;Tkem_rruE4)|#rE}2J=Bm8yd`>$UDti!n5kW)=mfYj!1csLgh@K(HIz4d4bDZ9T zzdggW21=JY(?qfV(J6tH@=DIX)7ICCtFb(Sv>Xu^Bdnp JFP!V1`wTw+9lrno delta 800 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 aviM(N@t<7BEX6O(#n05h4T41?Kyv^|PDYFX delta 130 zcmaFIv7B9fIWI340}y=Ao0KWU#K7u5|V&?iAr*22GL4lNk3+ zp2DQg$TN8lll^2?W?ya*pjt*CF22byIhJ{k$^}mO1)^6JO)uE^Tww9N$l`m2#rFe0 P2R~B-HwYF90o4Kk?qeOS diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 984f4c3dc252c12ad272641512dbcb41c54142c6..ddf012533cfd75782bc4afd9532d8e3911c126e4 100644 GIT binary patch delta 4900 zcmZ`-eN0=|6@Sk*Hej%gu`!?KLNM3~n6HqKgd~uULYqP;<^@ETBh!gsO>a6^Azhzks@uaw*5ub4{cS|?cDb; zhLB$T&U^QqbI&>VckU-&^}l)AbgQs1pMg>vza+d~chOX;DQ7RbU!68^`Js|A$8iVC zaK_h|$+KV_gmesHSE{qeZvOUPX1>2r_}*MTuMm}5Kk^HCx6McZ{J8c zn<#0dqzQ;@2t>jXe_j%Ep@x&z==Sw!0M-$v!Y5Lv3Ns^y7N zloKL8zks`e+erSM@2o`d6`)F)Vu24WJfEM{lY#P5-K-Xu-R(AdSgi(+kWj&b|U;bF6h4%jGJ#N>y51#W|mlDnS=lbLeS&PYqYQmcOuJ&InzA zM=kL@uI@EPvXPkzn|t3AgEO8V%iqVGbj6L5Ez=;=pIx!Mn2~dF6$|xqIcy4`zDNDQN znvT3@2~78>HUmPKAM;D#P6TIscs%5vL~i&N#w8Cr6TwId@`w*h0_M>;j&RX{Bt*iE z2%K?~G{)1s^6g!Tquq;okQj_$34JfhV=&j&v>8oAFej=O{U{)GW!#<<#Hc@ngfagp zH8hTSk$MY{f@48kdB|X)UYln-X91824E`dXp0y11D2d$@^44`MG1nG0M^q{Zj_ghoA-`- z8&O?bOH03}5%oa)Lx3biu1GdEqQTy#*7im;1X3Exz9K!tW5$Ai|?h6B@t)2SJi& ztRI^jQSEBPNPclUdy?!b-cf_ZaXujUL&6k*A%xLzbezX%aAk0aWU~1AY4a1I$~j7M zWJb;pMFReiZ`>~hWh2L{{RLcLFV6P=5ca?nll5v>rgG|9J6if>y&C*fjsmTmOQWTb zP8nL;R4|Qr2-@L&gOu*2ifXIc}kfJywn*|YePTwfx9IWshc2gw_pGmY&^^HfU zfn&sAJIp%CNn0m7Nq%f|4IyCviv!}($p)AjXZe66>%#sqUe1N;D2!xLE&v~a$k=#@ z2M2O~An3>bfW%`F)0VPsZ(q-lM~4GY!5sOYt!Y{=SPlEvERyp=FnYv*f1Ic1l?WDK zf+)SlbOZC~mDaL83?qZbYWHcM<-%n{5X{)PBT0y)jYaiVD;AaukFjd`v z0xej80grej`a|dZDC|djgwr7*BJlx#jcf&5%S(VSB%H>6JV~zG_t?8>ASJSXjF*BD z4)1{~E+t>tJB-v7E}*1^w3f6_D|t~;WB{g|xBq;AAEznA60K`R344k$J?JRelk+ID zK4}t$*fUf?zucQ#fOk9+7I|4m=cjDS=9bp+acY6WD(giF))rCDq3@HRPm>_Cf}F2R zcc0SStbVURBpc4DGfXyRB%`V(%ZtTeHnZxkdc*PXo02l)1(3GFBYvtS$Z=wz(pr$- z+P$QO_Yy-Z&kbcOk1h74oQy;f|3Lp`7h`j#iklvn)hsbg^MD3u(ZOX(?m7AlyYq(G zB~2GGmzHd;ZJIyy-pDUU5?gxj+wPBkT$OA(nrb?ltQkqwjLe$SsCKq6T@04kq8>I~ z*LJ5XRo6Y+Pijjy_)y)g+?%=cRg0P=+L1y#(zVU$I(NFFChhXv8o4<#A6zsfUEL{H zceb`B<;FQl9=%=SKVwcOda==e>4qLu#c^{Vg0 zi8Be;Xwo&Ba*fUoq#Z5@!rsfKH+C*orZztFw)qoV+2#I+HunRYJ3WmW($(lj(NDy* z(>?DG;nl#gz~kxmBEF)I;0Im;8CHtwWk3nj{ZNTW{e9|A+UR3Y^ygGH)A$xSMu>&Fc9 zrJgA+zuf%L>V9B#FWM4Tchb5mW!?4A+WWxTd%rMgJ(98>nK|%iv$1HlAyKhyvH$*# z#Ezp$<4DRllF*G{1a<-%AepiP;Oh+ewx*kWUt^k%u?tTe2IHEiz^QpEoLw0>8z%g4 zkA!mtJs2t5J%1k7ELf`pya&ONXL%D?1+iDw`$ch@mqh$B1o$p1>%>rWbgEo|TCwNL z!b*V-DJvS_OZ%}3fy+|1WAR^5^tWoNH(ek8Ge2E!gn0cz$14O~xjDBJG zx%naLet^2~mEP}6qC+WkC~?AKXz-2g_U zqPpzv^W}eK**yeR+6^1P>>+F?U6q^Iog`QpnvMczd5551W=dKpX`@8BKhwdCm7Ria z66(%SurI=k0}*Nec>(r_Rh^Z!FY}XlJ1DN{EH0rw96aMr`UzoL4aZKnX^AP|@-0=#4$ z9L@)2?f!uy9<3t4SE$NWs-nR^f*1KC^0F;t3E6r(s7RR}N@sLx=BN_>DJ5M%L>&;i z#i;o!gz>^lnW=~00pXv>ftt4rX|(Jy*uN;v a$`xMzviP7PKDb5h=^>Bu$ZN6eVH^g9vdp z?g)B}O)Qu5S%r=R*H=~??Syo*>&~Bxs756KyS6w~tstlK3sRas3EVgvb#--i!zhJ9 zjn)JMGra%$wS`@E1oe%$VOY+ zC-($6P~5Xeu7e{t9y$}YdHg&CL&;TY)`E?#_B>`Uy5vJEz%Mo*@LltPEqm83pcLME zgVP+-@YZ+RmDa|n$jOnS{fehSzsAXZx6SKdzy?O7(FmvY?hesvxgQohbpPf+U6}pF z6E?fGFe6@}HLAsT7eH5ZvjJ~kAXajJ*PR=ajeeOdbJxuC+%l=JFb@{3?7uF7#Mv!x zZ%<=8-0ko||3H2Xt&FihdV|g-nwJYHEuGIXYug+dWf$8*`+F?NO*Iz=fbi#dr>NlSl65oJY9(ex7PQHR-kZ9E(I-D0Z$H*8#plL@vcjI;Z~ zsgqVMtz{J5wNL(>Zk|4yjM?ZJu#}!em_(Qc&|A|gWX-~&l2c$O$i;s4QO7q)n0+;H zj3_J{=yPEnQS@`n%x(vQ-OkiyiApI=p(>q69hRr2CeOw!bPfgQ+1~;~tJH<^b(U_+ z6|$EUTHhacE#Sq>6qXb!PNRG7zkdH$d2wJRG9bbsC0Pv48kMu zs$ZDck2}AWTbchY$SpnGgBs2Yhr}9N6v_?|6TqZg=(GdHR>R?MUqI zP&IO_=HPs>2b|UC{|uq_5I%3=yn(7mydzWw>AmH5OVHJyEst9Ds1=X8;}g0o;>cUe z?-VOSVoOL=g+#@ZV1Ms^RY*)c-NU`#fVlsQHKhTdg zN;jk8V=z*&q(fjB;Xr-30O5z_fA$y1aUN;>2F6TvjfS4D0b~C+uvwC`>D)plznCv* zv;?z1W4ELI@WuR7Z=k#roh3(&1U-+62)zKEZkaxNW?DBVPd^tkQ=Fiy2;T#UnRJ_^ zs*0wv#lhk8cqY9?RWg`(RLK~%Vhn|kA{d`{OFcziM8@|Ko&Zp>zGKYSL)~rYT*#y^ zQHfrsH(>HL_F(W9{5`xBFOdESt}`?&;OG)Sqq6LqVv(W2XAL)h1*MD`!c;m0a$jJKTpmz=1>#NTpi3^Q0{<~=+ y3t5~|o}{k;kHD*5W#2gRE(?rIhRzbwQ{xaHm^qVBCH|Vp;9WMc^2n?O)%*|c3snIC diff --git a/core/migrations/0005_project_duration_project_estimated_budget_and_more.py b/core/migrations/0005_project_duration_project_estimated_budget_and_more.py new file mode 100644 index 0000000..087e4a8 --- /dev/null +++ b/core/migrations/0005_project_duration_project_estimated_budget_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 5.2.7 on 2026-02-16 02:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0004_cgiasset_physical_description_project_category_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='project', + name='duration', + field=models.CharField(blank=True, default='120 min', max_length=50), + ), + migrations.AddField( + model_name='project', + name='estimated_budget', + field=models.CharField(blank=True, default='$150M', max_length=100), + ), + migrations.AddField( + model_name='project', + name='rating', + field=models.CharField(default='PG-13', max_length=10), + ), + migrations.AddField( + model_name='scene', + name='image_url', + field=models.CharField(blank=True, max_length=500), + ), + ] diff --git a/core/migrations/__pycache__/0005_project_duration_project_estimated_budget_and_more.cpython-311.pyc b/core/migrations/__pycache__/0005_project_duration_project_estimated_budget_and_more.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..072b8183f467caaf71a97f163bd5a65d1fc5eea4 GIT binary patch literal 1373 zcmb7COK;Oa5MDcu6T1&uHx)vyprsWe5;SQ`#ifcwk*I`d8y@12%gXU?9jAVTwXHUl zkb2<2vEsr%C?Im+*q_j2B65g)<&;~hRvda_*Lgq_RK%`5JLB1JX8g^38X1uRT@!CV z7~dlR{9s0RMLWvbDpfuL1Q2Hei_38qpW`{egLQ!TcK}5&SEShXI-=Uwo|TIr;U!2$ zo6MQy1KBckqI!m7yMbsq2%E0f0fxs=$2hykv6L9(I0SM$;&d(-;Qa|jMr)9LgBsOg64y4ZuILfJJm)r1JU8Zk<&53od>BGx>p zsUFrHQiiIHpvBO!jw^^GzumM~`?1BP^o(WL%_aIz$w&~*o2tDN#1P(Aebb{2R`;NZ zZQUzSuN<}*+Ny;EA(YW=1Dhxq!>(soG$Vp}AL-cJkIpZyq&J#~h7ClP&DQs$+4cL2 z%S|?+NuG?*gN!nN)YY(!1Bph^G4zRPoYQfkSBAS+Hj`2ihhbs}0~yjELcWQqJ`CX- zUo}}V%tE+?ZG>&jz%F598^j+W^n?{j1ZGN)3n~fiKz2&FGrV8G8Fhk-VyfU+IOXSk z+w)U+4{N^Xkkqb2cHEMx;S_5_>i5v6XhT+dly_|ig zfQoY_`cQL!pmtA|tIAeQ*{UmBSEFw9P!EquRavVkYjtJq3e3&M_;e4GIG(F2nVOQR zE17=G?4%+dJY}2AbcxtZ3W0=*s;xTjY+9SDTkKkRca~}w@zwSWWXK#f>AV2< mH5IK0$8nTCE?EV42cMQW#fdF2C=TWN*!(GTod3le=KTdiJ6y2< literal 0 HcmV?d00001 diff --git a/core/models.py b/core/models.py index b24f06b..9a958fb 100644 --- a/core/models.py +++ b/core/models.py @@ -42,6 +42,11 @@ class Project(models.Model): created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) is_ai_generated = models.BooleanField(default=False) + + # New fields for "Super Production" + estimated_budget = models.CharField(max_length=100, blank=True, default="$150M") + rating = models.CharField(max_length=10, default="PG-13") + duration = models.CharField(max_length=50, blank=True, default="120 min") def save(self, *args, **kwargs): if not self.slug: @@ -66,6 +71,7 @@ class Scene(models.Model): title = models.CharField(max_length=255) description = models.TextField() visual_prompt = models.TextField(blank=True) + image_url = models.CharField(max_length=500, blank=True) class Meta: ordering = ['number'] @@ -120,4 +126,4 @@ class CgiAsset(models.Model): assigned_artist = models.CharField(max_length=100, blank=True) def __str__(self): - return f"{self.name} ({self.get_asset_type_display()})" \ No newline at end of file + return f"{self.name} ({self.get_asset_type_display()})" diff --git a/core/pexels.py b/core/pexels.py new file mode 100644 index 0000000..3be1c33 --- /dev/null +++ b/core/pexels.py @@ -0,0 +1,42 @@ +import os +import requests +from pathlib import Path + +API_KEY = os.getenv("PEXELS_KEY", "Vc99rnmOhHhJAbgGQoKLZtsaIVfkeownoQNbTj78VemUjKh08ZYRbf18") +CACHE_DIR = Path("static/images/pexels") + +def fetch_first(query: str, orientation: str = "landscape") -> dict | None: + if not API_KEY: + return None + + headers = {"Authorization": API_KEY} + url = "https://api.pexels.com/v1/search" + params = {"query": query, "orientation": orientation, "per_page": 1, "page": 1} + + try: + resp = requests.get(url, headers=headers, params=params, timeout=15) + resp.raise_for_status() + data = resp.json() + + photo = (data.get("photos") or [None])[0] + if not photo: + return None + + src = photo["src"].get("large2x") or photo["src"].get("large") or photo["src"].get("original") + CACHE_DIR.mkdir(parents=True, exist_ok=True) + target = CACHE_DIR / f"{photo['id']}.jpg" + + if src: + img_resp = requests.get(src, timeout=15) + img_resp.raise_for_status() + target.write_bytes(img_resp.content) + + return { + "id": photo["id"], + "local_path": f"images/pexels/{photo['id']}.jpg", + "photographer": photo.get("photographer"), + "photographer_url": photo.get("photographer_url"), + } + except Exception as e: + print(f"Error fetching from Pexels: {e}") + return None diff --git a/core/templates/base.html b/core/templates/base.html index e035667..5d2a961 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -49,6 +49,41 @@ .shadow-neon { box-shadow: 0 0 15px rgba(0, 229, 255, 0.2); } + .text-gradient-neon { + background: linear-gradient(45deg, var(--electric-cyan), var(--neon-purple)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + } + .btn-neon-purple { + background: var(--neon-purple); + color: white; + border: none; + box-shadow: 0 0 15px rgba(112, 0, 255, 0.3); + transition: all 0.3s ease; + } + .btn-neon-purple:hover { + background: #8221ff; + color: white; + box-shadow: 0 0 25px rgba(112, 0, 255, 0.5); + transform: scale(1.05); + } + .btn-outline-cyan { + border: 2px solid var(--electric-cyan); + color: var(--electric-cyan); + background: transparent; + transition: all 0.3s ease; + } + .btn-outline-cyan:hover { + background: var(--electric-cyan); + color: var(--bg-deep); + box-shadow: 0 0 20px rgba(0, 229, 255, 0.4); + } + .glass-card { + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 1.5rem; + } {% block extra_head %}{% endblock %} @@ -67,10 +102,13 @@ Command Center + @@ -81,7 +119,7 @@ {% if messages %}
{% for message in messages %} -
+
{{ message }}
{% endfor %} @@ -92,7 +130,7 @@
-

© 2026 CGI Virtual Studio. Secure Command Center.

+

© 2026 CGI Virtual Studio. Powered by AI Technology.

@@ -100,4 +138,4 @@ {% block extra_js %}{% endblock %} - + \ No newline at end of file diff --git a/core/templates/core/production_library.html b/core/templates/core/production_library.html new file mode 100644 index 0000000..9c98bed --- /dev/null +++ b/core/templates/core/production_library.html @@ -0,0 +1,90 @@ +{% extends 'base.html' %} +{% load static %} + +{% block content %} +
+
+
+

BIBLIOTECA STUDIO AI

+

Sua coleção de Super Produções geradas por Inteligência Artificial.

+
+ + NOVA PRODUÇÃO + +
+ +
+ {% for production in productions %} +
+
+
+ {% if production.thumbnail_url %} + {{ production.title }} + {% else %} +
+ +
+ {% endif %} +
+ {{ production.get_project_type_display }} +
+
+ {{ production.duration }} +
+
+
+
+

{{ production.title }}

+ {{ production.rating }} +
+

{{ production.category }} • {{ production.created_at|date:"d/m/Y" }}

+

{{ production.description }}

+
+ + ASSISTIR EXPERIÊNCIA + +
+ + Pipeline + + AI Generation v2.0 +
+
+
+
+
+ {% empty %} +
+
+
+ +
+

Ainda não há produções na sua biblioteca.

+

O Studio AI está pronto para transformar suas ideias em obras-primas.

+ COMEÇAR AGORA +
+
+ {% endfor %} +
+
+ + +{% endblock %} \ No newline at end of file diff --git a/core/templates/core/watch_production.html b/core/templates/core/watch_production.html new file mode 100644 index 0000000..b907d8d --- /dev/null +++ b/core/templates/core/watch_production.html @@ -0,0 +1,223 @@ +{% extends 'base.html' %} +{% load static %} + +{% block content %} + +
+ {% if project.thumbnail_url %} + {{ project.title }} + {% else %} +
+ {% endif %} + +
+
+
+ {{ project.get_project_type_display }} + {{ project.category }} + {{ project.rating }} +
+

{{ project.title }}

+
+ {{ project.duration }} + ORÇAMENTO: {{ project.estimated_budget }} +
+

{{ project.description }}

+
+ + +
+
+
+
+ +
+ +
+

ELENCO PRINCIPAL

+
+ {% for asset in project.assets.all %} + {% if asset.asset_type == 'CHAR' %} +
+
+
+
+ +
+

{{ asset.name }}

+

{{ asset.physical_description }}

+
+
+
+ {% endif %} + {% endfor %} +
+
+ + +
+

GALERIA DE CENAS

+
+ {% for scene in project.scenes.all %} +
+
+ {% if scene.image_url %} + {{ scene.title }} + {% else %} +
+ {% endif %} + +
+ CENA {{ scene.number }} +
{{ scene.title }}
+

{{ scene.description }}

+
+
+
+ {% endfor %} +
+
+ + +
+
+
+

ROTEIRO ORIGINAL

+
+
+
+ {{ project.full_script }} +
+
+
+
+ + +
+ + +
+
+ +
+
+

+

+
+
+ +
+ +
+ CENA 1 / {{ project.scenes.count }} +
+ +
+
+ + + + +{% endblock %} \ No newline at end of file diff --git a/core/urls.py b/core/urls.py index 9faee05..170c09e 100644 --- a/core/urls.py +++ b/core/urls.py @@ -8,5 +8,7 @@ urlpatterns = [ path('assets/', views.asset_library, name='asset_library'), path('studio-ai/', views.studio_ai, name='studio_ai'), path('generate-production/', views.generate_production, name='generate_production'), + path('library/', views.production_library, name='production_library'), + path('watch//', views.watch_production, name='watch_production'), path('project//', views.project_detail, name='project_detail'), -] \ No newline at end of file +] diff --git a/core/views.py b/core/views.py index 0f8f1ef..0232785 100644 --- a/core/views.py +++ b/core/views.py @@ -7,6 +7,7 @@ from django.contrib import messages from django.http import JsonResponse from .models import Project, PipelineStep, CgiAsset, StudioConfig, Scene from ai.local_ai_api import LocalAIApi +from .pexels import fetch_first def studio_admin_required(view_func): """Decorator to restrict access to studio admin only.""" @@ -47,37 +48,45 @@ def studio_ai(request): @studio_admin_required def generate_production(request): - """AI logic to create a full production automatically.""" + """AI logic to create a full SUPER PRODUCTION automatically.""" if request.method == "POST": category = request.POST.get("category", "Sci-Fi") proj_type = request.POST.get("project_type", "MOVIE") theme = request.POST.get("theme", "Future of humanity") prompt = f""" - Create a detailed production plan for a {proj_type} in the {category} category. + Create a detailed SUPER PRODUCTION plan for a {proj_type} in the {category} category. Theme: {theme} Requirements: 1. Unique Title and a compelling description. - 2. 3 Main Characters with names and detailed physical descriptions (based on REAL humans/actors style). - 3. 5 Key Scenes with titles and narrative descriptions. + 2. A full cinematic screenplay (script) for the entire production, ready to be read. + 3. A short query (2-4 words) for a cinematic visual image representing this production. + 4. 3 Main Characters with names and detailed physical descriptions (based on REAL humans/actors style). + 5. 8 Key Scenes with titles, narrative descriptions, and a unique 'visual_query' (2-4 words) for each scene. + 6. Metadata: Estimated budget (e.g., $200M), Age Rating (e.g., PG-13, R), and Duration (e.g., 140 min). Return the result ONLY in JSON format with the following structure: {{ "title": "...", "description": "...", + "full_script": "...", + "thumbnail_query": "...", + "budget": "...", + "rating": "...", + "duration": "...", "characters": [ {{"name": "...", "description": "...", "type": "CHAR"}} ], "scenes": [ - {{"title": "...", "description": "..."}} + {{"title": "...", "description": "...", "visual_query": "..."}} ] }} """ response = LocalAIApi.create_response({ "input": [ - {"role": "system", "content": "You are an expert Hollywood Producer and AI Cinema Director."}, + {"role": "system", "content": "You are an expert Hollywood Producer and AI Cinema Director specialized in Super Productions."}, {"role": "user", "content": prompt}, ], "text": {"format": {"type": "json_object"}}, @@ -87,20 +96,31 @@ def generate_production(request): try: data = LocalAIApi.decode_json_from_response(response) + # Fetch thumbnail from Pexels + thumbnail_data = fetch_first(data.get('thumbnail_query', data['title'])) + thumbnail_url = "" + if thumbnail_data: + thumbnail_url = thumbnail_data['local_path'] + # Create the Project project = Project.objects.create( title=data['title'], project_type=proj_type, category=category, description=data['description'], + full_script=data.get('full_script', ''), + thumbnail_url=thumbnail_url, is_ai_generated=True, - status='PRE' + status='DONE', + estimated_budget=data.get('budget', '$150M'), + rating=data.get('rating', 'PG-13'), + duration=data.get('duration', '120 min') ) # Create default Pipeline Steps stages = [s[0] for s in PipelineStep.STAGES] for stage in stages: - PipelineStep.objects.create(project=project, name=stage, progress=0) + PipelineStep.objects.create(project=project, name=stage, progress=100, is_completed=True) # Create Characters (Assets) for char in data['characters']: @@ -111,17 +131,26 @@ def generate_production(request): physical_description=char['description'] ) - # Create Scenes - for i, scene in enumerate(data['scenes']): + # Create Scenes and fetch images + for i, scene_data in enumerate(data['scenes']): + scene_image_url = "" + # Fetch image for EACH scene + v_query = scene_data.get('visual_query', scene_data['title']) + scene_img_data = fetch_first(f"{data['title']} {v_query}", orientation="landscape") + if scene_img_data: + scene_image_url = scene_img_data['local_path'] + Scene.objects.create( project=project, number=i+1, - title=scene['title'], - description=scene['description'] + title=scene_data['title'], + description=scene_data['description'], + visual_prompt=scene_data.get('visual_query', ''), + image_url=scene_image_url ) - messages.success(request, f"Super Produção '{project.title}' criada com sucesso pelo Studio AI!") - return redirect('project_detail', slug=project.slug) + messages.success(request, f"Super Produção '{project.title}' criada e salva na Biblioteca!") + return redirect('production_library') except Exception as e: messages.error(request, f"Erro ao processar resposta da AI: {str(e)}") @@ -130,6 +159,18 @@ def generate_production(request): return redirect('studio_ai') +@studio_admin_required +def production_library(request): + """View to see all completed AI productions.""" + productions = Project.objects.filter(is_ai_generated=True).order_by('-created_at') + return render(request, "core/production_library.html", {"productions": productions}) + +@studio_admin_required +def watch_production(request, slug): + """View to 'watch' (read and experience) a complete production.""" + project = get_object_or_404(Project.objects.prefetch_related('assets', 'scenes'), slug=slug) + return render(request, "core/watch_production.html", {"project": project}) + def admin_login(request): """View to enter the unique admin access key.""" if request.method == "POST": @@ -178,4 +219,4 @@ def project_detail(request, slug): "assets": project.assets.all(), "scenes": project.scenes.all(), } - return render(request, "core/project_detail.html", context) + return render(request, "core/project_detail.html", context) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index e22994c..80c2164 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ Django==5.2.7 mysqlclient==2.2.7 python-dotenv==1.1.1 +httpx