Toggle navigation
Toggle navigation
This project
Loading...
Sign in
卢阳
/
front_backend_zImage
Go to a project
Toggle navigation
Projects
Groups
Snippets
Help
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
ly0303521
2026-01-22 10:08:44 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
99677130dd429032565b984ffa9a83346adc7fcf
99677130
1 parent
439e47f9
参数化视频生成次数,修改config.js目录
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
94 additions
and
32 deletions
.env.sh
backend/main.py
z-image-generator/public/config.js → public/config.js
start_all.sh
z-image-generator/vite.config.ts
.env.sh
View file @
9967713
...
...
@@ -11,3 +11,7 @@ PUBLIC_ZIMAGE_PORT="39009"
# Local Ports (Internal Bind)
LOCAL_BACKEND_PORT
=
"7000"
LOCAL_FRONTEND_PORT
=
"7001"
# Business Logic Configuration
VIDEO_GENERATION_LIMIT
=
"1"
LIKES_FOR_REWARD
=
"5"
...
...
backend/main.py
View file @
9967713
...
...
@@ -4,9 +4,10 @@ import os
import
secrets
import
time
import
fcntl
import
re
from
pathlib
import
Path
from
threading
import
Lock
,
RLock
from
typing
import
List
,
Literal
,
Optional
from
typing
import
List
,
Literal
,
Optional
,
Dict
,
Any
import
httpx
from
fastapi
import
FastAPI
,
HTTPException
,
Query
...
...
@@ -25,6 +26,34 @@ GALLERY_MAX_ITEMS = int(os.getenv("GALLERY_MAX_ITEMS", "500"))
WHITELIST_PATH
=
Path
(
os
.
getenv
(
"WHITELIST_PATH"
,
Path
(
__file__
)
.
with_name
(
"whitelist.txt"
)))
ADMIN_ID
=
"86427531"
# Load dynamic limits from config.js
CONFIG_JS_PATH
=
Path
(
__file__
)
.
parent
.
parent
/
"public"
/
"config.js"
def
load_limits_from_config
()
->
dict
:
defaults
=
{
"VIDEO_GENERATION_LIMIT"
:
1
,
"LIKES_FOR_REWARD"
:
5
}
try
:
if
not
CONFIG_JS_PATH
.
exists
():
return
defaults
content
=
CONFIG_JS_PATH
.
read_text
(
encoding
=
"utf-8"
)
# Simple regex to extract values from JS object
# Looking for: VIDEO_GENERATION_LIMIT: 1
limit_match
=
re
.
search
(
r'VIDEO_GENERATION_LIMIT
\
s*:
\
s*(
\
d+)'
,
content
)
reward_match
=
re
.
search
(
r'LIKES_FOR_REWARD
\
s*:
\
s*(
\
d+)'
,
content
)
if
limit_match
:
defaults
[
"VIDEO_GENERATION_LIMIT"
]
=
int
(
limit_match
.
group
(
1
))
if
reward_match
:
defaults
[
"LIKES_FOR_REWARD"
]
=
int
(
reward_match
.
group
(
1
))
return
defaults
except
Exception
as
e
:
logger
.
error
(
f
"Failed to load config.js: {e}"
)
return
defaults
LIMITS
=
load_limits_from_config
()
# --- Usage Store ---
class
UsageStore
:
def
__init__
(
self
,
path
:
Path
):
...
...
@@ -191,14 +220,41 @@ class JsonStore:
if
not
target_item
:
return
None
liked_by
=
target_item
.
get
(
"likedBy"
,
[])
if
not
isinstance
(
liked_by
,
list
):
liked_by
=
[]
# --- New Reward Logic ---
# 1. Check current likes BEFORE change
current_likes_count
=
target_item
.
get
(
"likes"
,
0
)
author_id
=
target_item
.
get
(
"authorId"
)
is_liked_after
=
False
if
user_id
in
liked_by
:
# UNLIKE
liked_by
.
remove
(
user_id
)
target_item
[
"likes"
]
=
max
(
0
,
target_item
.
get
(
"likes"
,
0
)
-
1
)
new_likes_count
=
max
(
0
,
current_likes_count
-
1
)
is_liked_after
=
False
else
:
# LIKE
liked_by
.
append
(
user_id
)
target_item
[
"likes"
]
=
target_item
.
get
(
"likes"
,
0
)
+
1
new_likes_count
=
current_likes_count
+
1
is_liked_after
=
True
target_item
[
"likes"
]
=
new_likes_count
target_item
[
"likedBy"
]
=
liked_by
self
.
_write
(
data
)
# Reward Check: Only reward author when crossing threshold (e.g. 5, 10, 15...)
# We check if the NEW count is a multiple of LIKES_FOR_REWARD and we just increased it.
# (Simple version: Every N likes = 1 generation credit)
if
author_id
and
author_id
!=
"OFFICIAL"
and
author_id
!=
ADMIN_ID
:
limit
=
LIMITS
[
"LIKES_FOR_REWARD"
]
# Only reward on LIKE action, not unlike
if
is_liked_after
:
# Check if we just hit a multiple of the limit (5, 10, 15...)
if
new_likes_count
>
0
and
new_likes_count
%
limit
==
0
:
logger
.
info
(
f
"User {author_id} reached {new_likes_count} likes! Adding bonus."
)
usage_store
.
update_bonus
(
author_id
,
1
)
return
target_item
def
delete_item
(
self
,
item_id
:
str
)
->
bool
:
...
...
@@ -230,7 +286,13 @@ app.add_middleware(
)
@app.on_event
(
"startup"
)
async
def
startup
():
app
.
state
.
http
=
httpx
.
AsyncClient
(
timeout
=
httpx
.
Timeout
(
REQUEST_TIMEOUT_SECONDS
,
connect
=
5.0
))
async
def
startup
():
# Reload limits on startup to ensure fresh config
global
LIMITS
LIMITS
=
load_limits_from_config
()
logger
.
info
(
f
"Loaded limits: {LIMITS}"
)
app
.
state
.
http
=
httpx
.
AsyncClient
(
timeout
=
httpx
.
Timeout
(
REQUEST_TIMEOUT_SECONDS
,
connect
=
5.0
))
@app.on_event
(
"shutdown"
)
async
def
shutdown
():
await
app
.
state
.
http
.
aclose
()
@app.get
(
"/health"
)
...
...
@@ -244,29 +306,14 @@ async def login(user_id: str = Query(..., alias="userId")):
@app.post
(
"/likes/{item_id}"
)
async
def
toggle_like
(
item_id
:
str
,
user_id
:
str
=
Query
(
...
,
alias
=
"userId"
)):
is_liked_before
=
False
items
=
image_store
.
list_items
()
target_item
=
next
((
i
for
i
in
items
if
i
.
get
(
"id"
)
==
item_id
),
None
)
if
target_item
:
is_liked_before
=
user_id
in
target_item
.
get
(
"likedBy"
,
[])
# Try images first
updated_item
=
image_store
.
toggle_like
(
item_id
,
user_id
)
if
updated_item
:
is_liked_after
=
user_id
in
updated_item
.
get
(
"likedBy"
,
[])
if
is_liked_after
and
not
is_liked_before
:
usage_store
.
update_bonus
(
user_id
,
1
)
elif
not
is_liked_after
and
is_liked_before
:
usage_store
.
update_bonus
(
user_id
,
-
1
)
return
updated_item
if
updated_item
:
return
updated_item
# Then videos
updated_item
=
video_store
.
toggle_like
(
item_id
,
user_id
)
if
updated_item
:
is_liked_after
=
user_id
in
updated_item
.
get
(
"likedBy"
,
[])
if
is_liked_after
and
not
is_liked_before
:
usage_store
.
update_bonus
(
user_id
,
1
)
elif
not
is_liked_after
and
is_liked_before
:
usage_store
.
update_bonus
(
user_id
,
-
1
)
return
updated_item
if
updated_item
:
return
updated_item
raise
HTTPException
(
status_code
=
404
,
detail
=
"Item not found"
)
@app.get
(
"/usage/{user_id}"
)
...
...
@@ -274,11 +321,17 @@ async def get_user_usage(user_id: str):
try
:
usage
=
usage_store
.
get_usage
(
user_id
)
is_admin
=
user_id
==
ADMIN_ID
remaining
=
(
2
-
usage
[
"daily_used"
])
+
usage
[
"bonus_count"
]
if
not
is_admin
else
999999
limit
=
LIMITS
[
"VIDEO_GENERATION_LIMIT"
]
# Logic: base_limit - daily_used + bonus
remaining
=
(
limit
-
usage
[
"daily_used"
])
+
usage
[
"bonus_count"
]
if
is_admin
:
remaining
=
999999
return
{
"daily_used"
:
usage
[
"daily_used"
],
"bonus_count"
:
usage
[
"bonus_count"
],
"base_limit"
:
2
,
"base_limit"
:
limit
,
"remaining"
:
max
(
0
,
remaining
),
"is_admin"
:
is_admin
}
...
...
@@ -287,8 +340,8 @@ async def get_user_usage(user_id: str):
return
{
"daily_used"
:
0
,
"bonus_count"
:
0
,
"base_limit"
:
2
,
"remaining"
:
2
,
"base_limit"
:
LIMITS
[
"VIDEO_GENERATION_LIMIT"
],
"remaining"
:
LIMITS
[
"VIDEO_GENERATION_LIMIT"
],
"is_admin"
:
user_id
==
ADMIN_ID
}
...
...
@@ -371,4 +424,4 @@ async def remove_whitelist(user_id: str) -> dict:
# Redirect old /gallery to /gallery/images for backward compatibility
@app.get
(
"/gallery"
)
async
def
gallery
(
limit
:
int
=
Query
(
200
,
ge
=
1
,
le
=
1000
),
author_id
:
Optional
[
str
]
=
Query
(
None
,
alias
=
"authorId"
)):
return
await
gallery_images
(
limit
=
limit
,
author_id
=
author_id
)
\ No newline at end of file
return
await
gallery_images
(
limit
=
limit
,
author_id
=
author_id
)
...
...
z-image-generator/
public/config.js → public/config.js
View file @
9967713
...
...
@@ -2,5 +2,7 @@ window.APP_CONFIG = {
Z_IMAGE_DIRECT_BASE_URL
:
"http://106.120.52.146:39009"
,
TURBO_DIFFUSION_API_URL
:
"http://106.120.52.146:37002"
,
VIDEO_OSS_BASE_URL
:
"http://106.120.52.146:34000"
,
API_BASE_URL
:
"http://106.120.52.146:37000"
API_BASE_URL
:
"http://106.120.52.146:37000"
,
VIDEO_GENERATION_LIMIT
:
1
,
LIKES_FOR_REWARD
:
5
};
...
...
start_all.sh
View file @
9967713
...
...
@@ -12,7 +12,7 @@ fi
FRONTEND_DIR
=
"
$BASE_DIR
/z-image-generator"
BACKEND_DIR
=
"
$BASE_DIR
"
CONSTANTS_FILE
=
"
$FRONTEND_DIR
/constants.ts"
CONFIG_JS_FILE
=
"
$
FRONTEND
_DIR
/public/config.js"
CONFIG_JS_FILE
=
"
$
BASE
_DIR
/public/config.js"
LOGS_DIR
=
"
$BASE_DIR
/logs"
# Ensure logs directory exists
...
...
@@ -45,7 +45,9 @@ window.APP_CONFIG = {
Z_IMAGE_DIRECT_BASE_URL: "http://$PUBLIC_IP:$PUBLIC_ZIMAGE_PORT",
TURBO_DIFFUSION_API_URL: "http://$PUBLIC_IP:$PUBLIC_TURBO_PORT",
VIDEO_OSS_BASE_URL: "http://$PUBLIC_IP:$PUBLIC_OSS_PORT",
API_BASE_URL: "http://$PUBLIC_IP:$PUBLIC_BACKEND_PORT"
API_BASE_URL: "http://$PUBLIC_IP:$PUBLIC_BACKEND_PORT",
VIDEO_GENERATION_LIMIT: ${VIDEO_GENERATION_LIMIT:-1},
LIKES_FOR_REWARD: ${LIKES_FOR_REWARD:-5}
};
EOF
...
...
z-image-generator/vite.config.ts
View file @
9967713
...
...
@@ -9,6 +9,7 @@ export default defineConfig(({ mode }) => {
port
:
3000
,
host
:
'0.0.0.0'
,
},
publicDir
:
'../public'
,
plugins
:
[
react
()],
define
:
{
'process.env.API_KEY'
:
JSON
.
stringify
(
env
.
GEMINI_API_KEY
),
...
...
Please
register
or
login
to post a comment