Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
acharneski committed Nov 21, 2023
1 parent 162c759 commit 951081e
Show file tree
Hide file tree
Showing 31 changed files with 338 additions and 265 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@ package com.simiacryptus.skyenet.actors

import com.simiacryptus.skyenet.actors.record.*
import com.simiacryptus.skyenet.platform.DataStorage
import com.simiacryptus.skyenet.platform.SessionID
import com.simiacryptus.skyenet.platform.UserInfo
import com.simiacryptus.skyenet.util.FunctionWrapper
import com.simiacryptus.skyenet.util.JsonFunctionRecorder
import java.io.File

open class ActorSystem<T:Enum<*>>(
private val actors: Map<T, BaseActor<*>>,
private val dataStorage: DataStorage,
val userId: String?,
val sessionId: String
val userId: UserInfo?,
val sessionId: SessionID
) {
val sessionDir = dataStorage.getSessionDir(userId, sessionId)
fun getActor(actor: T): BaseActor<*> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,6 @@ import java.util.HashMap

open class AuthenticationManager {

data class UserInfo(
val id: String,
val email: String,
val name: String,
val picture: String
)

private val users = HashMap<String, UserInfo>()

open fun getUser(sessionId: String?) = if (null == sessionId) null else users[sessionId]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ open class AuthorizationManager {

open fun isAuthorized(
applicationClass: Class<*>?,
user: String?,
user: UserInfo?,
operationType: OperationType,
) = try {
if (isUserAuthorized("/permissions/${operationType.name.lowercase(Locale.getDefault())}.txt", user)) {
if (isUserAuthorized("/permissions/${operationType.name.lowercase(Locale.getDefault())}.txt", user?.email)) {
log.debug("User {} authorized for {} globally", user, operationType)
true
} else if (null != applicationClass) {
val packagePath = applicationClass.`package`.name.replace('.', '/')
val opName = operationType.name.lowercase(Locale.getDefault())
if (isUserAuthorized("/$packagePath/$opName.txt", user)) {
if (isUserAuthorized("/$packagePath/$opName.txt", user?.email)) {
log.debug("User {} authorized for {} on {}", user, operationType, applicationClass)
true
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ open class DataStorage(
) {

open fun <T> getJson(
userId: String?,
sessionId: String,
userId: UserInfo?,
sessionId: SessionID,
clazz: Class<T>,
filename: String
): T? {
Expand All @@ -23,27 +23,27 @@ open class DataStorage(
}

open fun getMessages(
userId: String?,
sessionId: String
userId: UserInfo?,
sessionId: SessionID
): LinkedHashMap<String, String> {
validateSessionId(sessionId)
val messageDir = File(this.getSessionDir(userId, sessionId), MESSAGE_DIR)
val messages = LinkedHashMap<String, String>()
log.debug("Loading messages for $sessionId: ${messageDir.absolutePath}")
log.debug("Loading messages for {}: {}", sessionId, messageDir.absolutePath)
messageDir.listFiles()?.sortedBy { it.lastModified() }?.forEach { file ->
val message = JsonUtil.objectMapper().readValue(file, String::class.java)
messages[file.nameWithoutExtension] = message
}
log.debug("Loaded ${messages.size} messages for $sessionId")
log.debug("Loaded {} messages for {}", messages.size, sessionId)
return messages
}

open fun getSessionDir(
userId: String?,
sessionId: String
userId: UserInfo?,
sessionId: SessionID
): File {
validateSessionId(sessionId)
val parts = sessionId.split("-")
val parts = sessionId.sessionId.split("-")
return when (parts.size) {
3 -> {
val root = when {
Expand All @@ -52,17 +52,17 @@ open class DataStorage(
else -> throw IllegalArgumentException("Invalid session ID: $sessionId")
}
val dateDir = File(root, parts[1])
log.debug("Date Dir for $sessionId: ${dateDir.absolutePath}")
log.debug("Date Dir for {}: {}", sessionId, dateDir.absolutePath)
val sessionDir = File(dateDir, parts[2])
log.debug("Instance Dir for $sessionId: ${sessionDir.absolutePath}")
log.debug("Instance Dir for {}: {}", sessionId, sessionDir.absolutePath)
sessionDir
}

2 -> {
val dateDir = File(dataDir, parts[0])
log.debug("Date Dir for $sessionId: ${dateDir.absolutePath}")
log.debug("Date Dir for {}: {}", sessionId, dateDir.absolutePath)
val sessionDir = File(dateDir, parts[1])
log.debug("Instance Dir for $sessionId: ${sessionDir.absolutePath}")
log.debug("Instance Dir for {}: {}", sessionId, sessionDir.absolutePath)
sessionDir
}

Expand All @@ -73,8 +73,8 @@ open class DataStorage(
}

open fun getSessionName(
userId: String?,
sessionId: String
userId: UserInfo?,
sessionId: SessionID
): String {
validateSessionId(sessionId)
val userMessage = File(this.getSessionDir(userId, sessionId), MESSAGE_DIR).listFiles()
Expand All @@ -84,38 +84,38 @@ open class DataStorage(
val fileText = messageFile.readText()
val split = fileText.split("<p>")
if (split.size < 2) {
log.debug("Session $sessionId: No messages")
log.debug("Session {}: No messages", sessionId)
""
} else {
val stringList = split[1].split("</p>")
if (stringList.isEmpty()) {
log.debug("Session $sessionId: No messages")
log.debug("Session {}: No messages", sessionId)
""
} else {
stringList.first()
}
}
}?.firstOrNull { it.isNotEmpty() }
return if (null != userMessage) {
log.debug("Session $sessionId: $userMessage")
log.debug("Session {}: {}", sessionId, userMessage)
userMessage
} else {
log.debug("Session $sessionId: No messages")
sessionId
log.debug("Session {}: No messages", sessionId)
sessionId.sessionId
}
}

open fun listSessions(
userId: String?
): List<String> {
userId: UserInfo?
): List<SessionID> {
val globalSessions = listSessions(dataDir)
val userSessions = if (userId == null) listOf() else listSessions(userRoot(userId))
return globalSessions.map { "G-$it" } + userSessions.map { "U-$it" }
return globalSessions.map { SessionID("G-$it") } + userSessions.map { SessionID("U-$it") }
}

open fun <T : Any> setJson(
userId: String?,
sessionId: String,
userId: UserInfo?,
sessionId: SessionID,
settings: T,
filename: String
): T {
Expand All @@ -127,27 +127,19 @@ open class DataStorage(
}

open fun updateMessage(
userId: String?,
sessionId: String,
userId: UserInfo?,
sessionId: SessionID,
messageId: String,
value: String
) {
validateSessionId(sessionId)
val file = File(File(this.getSessionDir(userId, sessionId), MESSAGE_DIR), "$messageId.json")
log.debug("Updating message for $sessionId / $messageId: ${file.absolutePath}")
log.debug("Updating message for {} / {}: {}", sessionId, messageId, file.absolutePath)
file.parentFile.mkdirs()
JsonUtil.objectMapper().writeValue(file, value)
}

open fun validateSessionId(
sessionId: String
) {
if (!sessionId.matches("""([GU]-)?\d{8}-\w{8}""".toRegex())) {
throw IllegalArgumentException("Invalid session ID: $sessionId")
}
}

private fun listSessions(dir: File): List<String> {
private fun listSessions(dir: File): List<SessionID> {
val files = dir.listFiles()?.flatMap { it.listFiles()?.toList() ?: listOf() }?.filter { sessionDir ->
val operationDir = File(sessionDir, MESSAGE_DIR)
if (!operationDir.exists()) false else {
Expand All @@ -156,36 +148,42 @@ open class DataStorage(
}
}
log.debug("Sessions: {}", files?.map { it.parentFile.name + "-" + it.name })
return files?.map { it.parentFile.name + "-" + it.name } ?: listOf()
return files?.map { SessionID(it.parentFile.name + "-" + it.name) } ?: listOf()
}

private fun userRoot(userId: String?) = File(
private fun userRoot(userId: UserInfo?) = File(
File(dataDir, "users"),
userId ?: throw IllegalArgumentException("User ID required for private session")
userId?.email ?: throw IllegalArgumentException("User required for private session")
)

companion object {

private val log = org.slf4j.LoggerFactory.getLogger(DataStorage::class.java)

fun newGlobalID(): String {
fun validateSessionId(
sessionId: SessionID
) {
if (!sessionId.sessionId.matches("""([GU]-)?\d{8}-\w{8}""".toRegex())) {
throw IllegalArgumentException("Invalid session ID: $sessionId")
}
}

fun newGlobalID(): SessionID {
val uuid = UUID.randomUUID().toString().split("-").first()
val yyyyMMdd = java.time.LocalDate.now().toString().replace("-", "")
log.debug("New ID: $yyyyMMdd-$uuid")
return "G-$yyyyMMdd-$uuid"
return SessionID("G-$yyyyMMdd-$uuid")
}

fun newUserID(): String {
fun newUserID(): SessionID {
val uuid = UUID.randomUUID().toString().split("-").first()
val yyyyMMdd = java.time.LocalDate.now().toString().replace("-", "")
log.debug("New ID: $yyyyMMdd-$uuid")
return "U-$yyyyMMdd-$uuid"
return SessionID("U-$yyyyMMdd-$uuid")
}

private const val MESSAGE_DIR = "messages"
fun String.stripPrefix(prefix: String) = if (!this.startsWith(prefix)) this else {
this.substring(prefix.length)
}

}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.simiacryptus.skyenet.platform

import com.simiacryptus.skyenet.platform.DataStorage.Companion.validateSessionId

data class SessionID(
val sessionId: String
) {
init {
validateSessionId(this)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ open class UsageManager {
private val scheduler = Executors.newSingleThreadScheduledExecutor()
private val txLogFile = File(".skyenet/usage/log.csv")
@Volatile private var txLogFileWriter: FileWriter?
private val usagePerSession = HashMap<String, UsageCounters>()
private val sessionsByUser = HashMap<String, HashSet<String>>()
private val usersBySession = HashMap<String, HashSet<String>>()
private val usagePerSession = HashMap<SessionID, UsageCounters>()
private val sessionsByUser = HashMap<UserInfo, HashSet<SessionID>>()
private val usersBySession = HashMap<SessionID, HashSet<UserInfo>>()

init {
txLogFile.parentFile.mkdirs()
Expand All @@ -40,15 +40,15 @@ open class UsageManager {
?: throw RuntimeException("Unknown model $model")
when (direction) {
"input" -> incrementUsage(
sessionId,
user,
SessionID(sessionId),
UserInfo(email=user),
modelEnum,
OpenAIClient.Usage(prompt_tokens = tokens.toInt())
)

"output" -> incrementUsage(
sessionId,
user,
SessionID(sessionId),
UserInfo(email=user),
modelEnum,
OpenAIClient.Usage(completion_tokens = tokens.toInt())
)
Expand All @@ -63,7 +63,7 @@ open class UsageManager {
}

@Suppress("MemberVisibilityCanBePrivate")
open fun writeCompactLog(file: File) {
protected open fun writeCompactLog(file: File) {
val writer = FileWriter(file)
usagePerSession.forEach { (sessionId, usage) ->
val user = usersBySession[sessionId]?.firstOrNull()
Expand Down Expand Up @@ -107,7 +107,8 @@ open class UsageManager {
File(".skyenet/usage/counters.json").writeText(JsonUtil.toJson(usagePerSession))
}

open fun incrementUsage(sessionId: String, user: String?, model: OpenAIModel, tokens: OpenAIClient.Usage) {
open fun incrementUsage(sessionId: SessionID, user: UserInfo?, model: OpenAIModel, tokens: OpenAIClient.Usage) {
@Suppress("NAME_SHADOWING") val user = if(null == user) null else UserInfo(email= user.email) // Hack
val usage = usagePerSession.getOrPut(sessionId) {
UsageCounters()
}
Expand Down Expand Up @@ -135,8 +136,9 @@ open class UsageManager {
}
}

open fun getUserUsageSummary(user: String): Map<OpenAIModel, OpenAIClient.Usage> =
sessionsByUser[user]?.flatMap { sessionId ->
open fun getUserUsageSummary(user: UserInfo): Map<OpenAIModel, OpenAIClient.Usage> {
@Suppress("NAME_SHADOWING") val user = if(null == user) null else UserInfo(email= user.email) // Hack
return sessionsByUser[user]?.flatMap { sessionId ->
val usage = usagePerSession[sessionId]
usage?.tokensPerModel?.entries?.map { (model, counter) ->
model.model to counter.toUsage()
Expand All @@ -149,8 +151,9 @@ open class UsageManager {
)
}
} ?: emptyMap()
}

open fun getSessionUsageSummary(sessionId: String): Map<OpenAIModel, OpenAIClient.Usage> =
open fun getSessionUsageSummary(sessionId: SessionID): Map<OpenAIModel, OpenAIClient.Usage> =
usagePerSession[sessionId]?.tokensPerModel?.entries?.map { (model, counter) ->
model.model to counter.toUsage()
}?.groupBy { it.first }?.mapValues { it.value.map { it.second }.reduce { a, b ->
Expand All @@ -161,8 +164,8 @@ open class UsageManager {
} } ?: emptyMap()

data class UsageKey(
val sessionId: String,
val user: String?,
val sessionId: SessionID,
val user: UserInfo?,
val model: OpenAIModel,
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.simiacryptus.skyenet.platform

data class UserInfo(
val email: String,
val id: String? = null, // TODO: Remove default value
val name: String? = null, // TODO: Remove default value
val picture: String? = null, // TODO: Remove default value
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ open class UserSettingsManager {
val apiKey: String = "",
)

private val userSettings = HashMap<String, UserSettings>()
private val userSettings = HashMap<UserInfo, UserSettings>()
private val userConfigDirectory = File(".skyenet/users")

open fun getUserSettings(user: String): UserSettings {
open fun getUserSettings(user: UserInfo): UserSettings {
return userSettings.getOrPut(user) {
val file = File(userConfigDirectory, "$user.json")
if (file.exists()) {
Expand All @@ -24,7 +24,7 @@ open class UserSettingsManager {
}
}

open fun updateUserSettings(user: String, settings: UserSettings) {
open fun updateUserSettings(user: UserInfo, settings: UserSettings) {
userSettings[user] = settings
val file = File(userConfigDirectory, "$user.json")
file.parentFile.mkdirs()
Expand Down
Loading

0 comments on commit 951081e

Please sign in to comment.